Java捕获ThreadPoolExecutor内部线程异常的四种方法
作者:大大怪~将军
这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下
方案 1
使用 execute + try-catch 记录异常
import java.util.concurrent.*;
public class ThreadPoolExceptionDemo {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactory() {
private int count = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "custom-thread-" + count++);
}
});
executor.execute(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
throw new RuntimeException("任务异常");
} catch (Exception e) {
System.err.println("线程 " + Thread.currentThread().getName() + " 捕获异常: " + e.getMessage());
e.printStackTrace();
}
});
executor.shutdown();
}
}方案 2
使用 submit + Future
submit() 方法返回 Future,可以通过 get() 方法捕获异常:
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<?> future = executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
throw new RuntimeException("任务异常");
});
try {
future.get(); // get() 会抛出 ExecutionException
} catch (InterruptedException | ExecutionException e) {
System.err.println("线程 " + Thread.currentThread().getName() + " 捕获异常: " + e.getCause().getMessage());
e.printStackTrace();
}
executor.shutdown();
}注意
- get() 方法会阻塞主线程直到任务完成。
- ExecutionException 的 getCause() 方法可以获取原始异常。
方案 3
自定义 UncaughtExceptionHandler
可以为线程设置 UncaughtExceptionHandler,当 Runnable 没有捕获异常时,ThreadPoolExecutor 也不会吞掉异常:
public class ThreadPoolWithExceptionHandler {
public static void main(String[] args) {
ThreadFactory threadFactory = r -> {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("线程 " + thread.getName() + " 发生异常: " + throwable.getMessage());
throwable.printStackTrace();
});
return t;
};
ExecutorService executor = new ThreadPoolExecutor(
2, 4, 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
threadFactory
);
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
throw new RuntimeException("任务异常");
});
executor.shutdown();
}
}方案 4
重写 afterExecute 方法
如果你要在 ThreadPoolExecutor 内部直接处理异常,可以继承 ThreadPoolExecutor 并重写 afterExecute():
class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
((Future<?>) r).get(); // 获取任务结果,捕获异常
} catch (InterruptedException | ExecutionException e) {
t = e.getCause();
}
}
if (t != null) {
System.err.println("线程 " + Thread.currentThread().getName() + " 发生异常: " + t.getMessage());
t.printStackTrace();
}
}
}
public class ThreadPoolAfterExecuteDemo {
public static void main(String[] args) {
ThreadPoolExecutor executor = new CustomThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
throw new RuntimeException("任务异常");
});
executor.shutdown();
}
}结论
| 方案 | 适用场景 | 缺点 |
|---|---|---|
| try-catch 手动处理 | 适用于 execute() | 代码侵入性强,所有任务都要加 try-catch |
| Future.get() 捕获异常 | 适用于 submit() | get() 会阻塞主线程 |
| UncaughtExceptionHandler | 适用于 execute() | 不能捕获 submit() 提交的异常 |
| afterExecute() | 适用于 execute() 和 submit() | 需要继承 ThreadPoolExecutor |
推荐:
- 任务内部
try-catch适用于execute() Future.get()适用于submit()- 统一异常处理建议使用
afterExecute()或UncaughtExceptionHandler
到此这篇关于Java捕获ThreadPoolExecutor内部线程异常的四种方法的文章就介绍到这了,更多相关Java ThreadPoolExecutor异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
