在Eclipse中抛出未经检查的异常时,从新创建的线程打印堆栈跟踪

时间:2013-05-29 15:02:17

标签: java exception concurrency

当从不同于主线程的线程抛出未经检查的异常时,为什么我无法在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当然真的很难看。

2 个答案:

答案 0 :(得分: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();是解决这个问题的典型方法。

答案 1 :(得分:1)

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

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

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