当从不同于主线程的线程抛出未经检查的异常时,为什么我无法在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当然真的很难看。
答案 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()
将阻止,直到任务被取消或抛出异常,因此您可能希望在单独的线程中调用它。