0

为什么当从与主线程不同的线程抛出未经检查的异常时,我无法在 Eclipse 的控制台中看到堆栈跟踪?

例如:

ScheduledThreadPoolExecutor scheduledExecutor;
scheduledExecutor.scheduleAtFixedRate(new Log(), 0, LOGGING_FREQUENCY_MS, TimeUnit.MILLISECONDS);
public class Log implements Runnable {
        public void run() {
     //NullPointerException is thrown
     }
}

我没有输出。但如果我这样做:

ScheduledThreadPoolExecutor scheduledExecutor;
scheduledExecutor.scheduleAtFixedRate(new Log(), 0, LOGGING_FREQUENCY_MS, TimeUnit.MILLISECONDS);
public class Log implements Runnable {
        public void run() {
        try {
        //NullPointerException is thrown
        }catch(Exception e){
             e.printStackTrace();
        }
    }
}

我可以看到堆栈跟踪。

为什么?

编辑:后续问题:打印线程池线程抛出的异常的最简单方法是什么?将 try-catch 添加到每个 Runnable 中当然非常难看。

4

2 回答 2

4

为什么当从与主线程不同的线程抛出未经检查的异常时,我无法在 Eclipse 的控制台中看到堆栈跟踪?

因为它是未经检查的。默认情况下,不会打印线程池线程抛出的异常。

如果您想查看异常,则需要执行以下操作:

Future future = scheduledExecutor.submit(...);
...
try {
   // wait for the run() method to finish normally or with a throw
   future.get();
} catch (ExecutionException e) {
   // the cause of this exception is the one that is thrown by the run()
   Throwable cause = e.getCause();
   cause.printStackTrace();
}

编辑:后续问题:打印线程池线程抛出的异常的最简单方法是什么?将 try-catch 添加到每个 Runnable 中当然非常难看。

您不需要将 try/catch 添加到 中Runnable,只需将其添加到启动池的人即可。

另一种解决方案是编写一些RunnableWrapper打印异常的代码:

public void RunnableWrapper implements Runnable {
     private Runnable delegate;
     public RunnableWrapper(Runnable delegate) {
       this.delegate = delegate;
     }
     public void run() {
         try {
            delegate.run();
         } catch (Throwable t) {
             t.printStackTrace();
         }
     }
 }

然后你可以这样做:

 scheduledExecutor.submit(new RunnableWrapper(myTask));

但这future.get();是解决这个问题的典型方法。

于 2013-05-29T15:09:03.960 回答
1

因为 Executor 已经“吞下了”异常。您可以通过查询返回的未来来查看是否有一个:

Future<?> f = scheduledExecutor.scheduleAtFixedRate(new Log(),...);
try {
    f.get();
} catch (ExecutionException e) {
    Throwable actualException = e.getCause();
}

请注意,这f.get()将一直阻塞,直到任务被取消或引发异常,因此您可能希望在单独的线程中调用它。

于 2013-05-29T15:10:13.947 回答