将异常从一个线程重新抛出到另一个线程

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&lt;?&gt; 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&lt;?&gt; future = CompletableFuture.runAsync(() -&gt; /* your operation */ , yourExecutor);,那么,你不仅可以使用isDone()来检查一般情况下是否完成,还可以使用例如if(future.isCompletedExceptionally()) future.join();重投。

以上是关于将异常从一个线程重新抛出到另一个线程的主要内容,如果未能解决你的问题,请参考以下文章

SWIG:将异常从 Python 抛出到 C++

将 webview 请求抛出到另一个 webview

从线程抛出异常并没有给出预期的结果

跨线程异常抛出

XmlDocument.Save 从 GC 线程抛出的未处理异常

C# - 线程中止异常(Thread Abort Exception)重新抛出自身