1. 看一下几种提交任务API的异常处理结果
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(1);
threadPool.submit(() -> {
throw new RuntimeException("test");
});
Future<Object> future = threadPool.submit(() -> {
throw new RuntimeException("test");
});
try {
future.get();
} catch (Exception e) {
System.out.println("future.get() 出现了异常");
}
threadPool.execute(()->{
throw new RuntimeException("test");
});
// future.get() 出现了异常
// Exception in thread "pool-1-thread-1" java.lang.RuntimeException: test
// at com.hdu.Main.lambda$main$2(Main.java:27)
// at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
// at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
// at java.lang.Thread.run(Thread.java:748)
}
如你所见,sumbit()默认会吞掉异常,除非你主动 get()。这也符合 future的设计逻辑。 对于 execute()来说,他会直接抛出异常。
2. 优雅处理异常
public static void testHandleException() {
ExecutorService threadPool = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2,
1,
SECONDS,
new LinkedBlockingQueue<>(100)
) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
if (t != null) {
System.out.println(t.getMessage());
}
if (t == null && r instanceof Future) {
try {
if (((Future<?>) r).isDone()) {
((Future<?>) r).get();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
};
threadPool.submit(() -> {
throw new RuntimeException("submitException");
});
Future<Object> future = threadPool.submit(() -> {
throw new RuntimeException("submitAndGetException");
});
try {
future.get();
} catch (Exception e) {
System.out.println("future.get() 出现了异常");
}
threadPool.execute(() -> {
throw new RuntimeException("execute Exception");
});
// java.lang.RuntimeException: submitException
// java.lang.RuntimeException: submitAndGetException
// future.get() 出现了异常
// execute Exception
// Exception in thread "pool-1-thread-3" java.lang.RuntimeException: execute Exception
// at com.hdu.Main.lambda$testHandleException$2(Main.java:54)
// at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
// at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
// at java.lang.Thread.run(Thread.java:748)
}
重写 afterExecute 逻辑,感知线程池出现异常。
3.说在最后
其实建议在每个任务执行的过程中自己去处理异常,而不是将异常抛给线程池。为什么这么说呢?其实线程池内部如果线程出现了异常都会回收掉出现异常的线程,然后创建新的线程补充上去。这是影响性能的
4.源码
handleThreadPoolException: handleThreadPoolException (gitee.com)