面试题答案
一键面试捕获并处理线程池内线程抛出异常的方式
- 使用try - catch块包裹提交任务
在向线程池提交任务时,使用
try - catch
块包裹提交代码。例如:
ExecutorService executorService = Executors.newFixedThreadPool(10);
try {
Future<?> future = executorService.submit(() -> {
// 可能抛出异常的任务代码
throw new RuntimeException("任务异常");
});
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
优点:实现简单,直观易懂,能直接捕获任务执行过程中的异常。
缺点:如果任务是异步执行且不需要获取返回值,使用future.get()
会导致主线程阻塞等待任务完成,影响程序性能。
- 重写ThreadPoolExecutor的afterExecute方法
继承
ThreadPoolExecutor
并重写afterExecute
方法。
class CustomThreadPool extends ThreadPoolExecutor {
public CustomThreadPool(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) {
System.out.println("捕获到任务异常: " + t.getMessage());
}
}
}
优点:无需阻塞主线程,能在任务执行完成后统一处理异常,适用于各种任务提交方式。
缺点:需要继承ThreadPoolExecutor
,侵入性相对较大,如果项目中有多个线程池,需要分别继承处理。
- 使用UncaughtExceptionHandler
为线程池中的线程设置
UncaughtExceptionHandler
。
ExecutorService executorService = Executors.newFixedThreadPool(10);
ThreadFactory threadFactory = Executors.defaultThreadFactory();
for (int i = 0; i < 10; i++) {
Thread thread = threadFactory.newThread(() -> {
// 可能抛出异常的任务代码
throw new RuntimeException("任务异常");
});
thread.setUncaughtExceptionHandler((t, e) -> {
System.out.println("捕获到任务异常: " + e.getMessage());
});
executorService.submit(thread);
}
优点:提供了一种灵活的异常处理方式,不影响任务的正常执行流程,适用于需要对每个线程进行独立异常处理的场景。
缺点:如果线程池规模较大,为每个线程设置UncaughtExceptionHandler
会增加代码复杂度,且需要手动管理线程的创建和提交。