将异常从一个线程重新抛出到另一个线程
Posted
技术标签:
【中文标题】将异常从一个线程重新抛出到另一个线程【英文标题】:Rethrowing exception from one thread to another 【发布时间】:2022-01-09 07:46:05 【问题描述】:我有一个场景,我希望一个线程执行一些循环操作,而第二个(主)线程执行一些其他循环工作,而第一个线程仍在执行其工作。
我的想法是使用CountDownLatch
并等待它在主线程中完成:
public void process()
CountDownLatch countDownLatch = new CountDownLatch(10_000);
Future<?> future = Executors.newSingleThreadExecutor().submit(() ->
for (int i = 0; i < 10_000; i++)
// do some stuff
countDownLatch.countDown();
);
try
while (!countDownLatch.await(5, SECONDS))
// do some other stuff...
catch (InterruptedException e)
Thread.currentThread().interrupt();
问题是有时可能会在第一个(未来)线程中引发异常,在这种情况下,继续在主线程中执行代码也没有意义。
我正在考虑将此类异常的引用(从第一个线程抛出)分配给 volatile 字段,并在 main 的线程循环中对该字段进行空检查,以查看它是否应该继续循环:
private volatile Exception innerException;
public void process()
CountDownLatch countDownLatch = new CountDownLatch(10_000);
Future<?> future = Executors.newSingleThreadExecutor().submit(() ->
try
for (int i = 0; i < 10_000; i++)
// do some stuff
countDownLatch.countDown();
catch (Exception e)
this.innerException = e;
throw e;
);
try
while (!countDownLatch.await(1, SECONDS))
// do some other stuff... but it doesn't make sense to continue
// if 'future' has thrown an exception, so let's rethrow it:
if (innerException != null)
throw innerException;
catch (InterruptedException e)
Thread.currentThread().interrupt();
catch (Exception e)
log.error("Something bad happened in the 'future'! : ", e);
我想知道这是否是一个好(安全?)的想法,或者也许有一些更好的方法来解决这类问题?
感谢任何对此的帮助,谢谢!
【问题讨论】:
【参考方案1】:您可以使用 future.get 在未来完成时进行同步。如果 Runnable/Callable 抛出异常,future.get 将抛出 ExecutionException。您可以完全摆脱 CountDownLatch。
【讨论】:
是的,这听起来是个好主意,所以我猜你在主循环中考虑这样的事情:while (!isFinished(future)) // do some other stuff...
并检查未来是否已经完成:private static boolean isFinished(Future<?> future) try future.get(1, SECONDS); return true; catch (TimeoutException e) return false; catch (ExecutionException e) throw new RuntimeException(e);
谢谢建议!
future 上有一个 'isDone' 方法,可用于检查 future 是否准备好。我不确定在某个循环中检查 isDone 是否是最好的方法;这将取决于情况。
或者使用CompletableFuture<?> future = CompletableFuture.runAsync(() -> /* your operation */ , yourExecutor);
,那么,你不仅可以使用isDone()
来检查一般情况下是否完成,还可以使用例如if(future.isCompletedExceptionally()) future.join();
重投。以上是关于将异常从一个线程重新抛出到另一个线程的主要内容,如果未能解决你的问题,请参考以下文章