面试题答案
一键面试异常处理策略
- 任务执行异常处理:使用
Thread.UncaughtExceptionHandler
来捕获线程池线程执行任务时未捕获的异常。这样可以确保即使任务抛出异常,线程池中的线程不会直接终止,线程池能够继续正常工作。 - 记录异常信息:在
UncaughtExceptionHandler
中,使用日志框架(如log4j
或slf4j
)记录详细的异常信息,包括异常类型、堆栈跟踪等,以便后续排查问题。 - 自定义任务包装类:为了更好地控制任务执行过程,特别是对于不同类型任务的异常处理,可以创建一个自定义的任务包装类,在其中添加特定于任务的异常处理逻辑。
关键代码片段
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadPoolExceptionHandling {
private static final Logger logger = Logger.getLogger(ThreadPoolExceptionHandling.class.getName());
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
// 设置全局默认的UncaughtExceptionHandler
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e);
}
});
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
int taskNumber = i;
executorService.submit(new TaskWithExceptionHandling(taskNumber));
}
executorService.shutdown();
}
static class TaskWithExceptionHandling implements Runnable {
private final int taskNumber;
public TaskWithExceptionHandling(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
try {
// 模拟可能抛出异常的任务
if (taskNumber % 3 == 0) {
throw new RuntimeException("Task " + taskNumber + " failed with an exception");
}
System.out.println("Task " + taskNumber + " executed successfully");
} catch (Exception e) {
// 任务内自定义异常处理逻辑
logger.log(Level.SEVERE, "Exception in task " + taskNumber, e);
// 可以选择在这里进行一些恢复操作,比如重试任务等
}
}
}
}
在上述代码中:
Thread.setDefaultUncaughtExceptionHandler
设置了全局的未捕获异常处理器,用于捕获线程池线程执行任务时未处理的异常,并记录日志。TaskWithExceptionHandling
类是一个自定义的任务类,在run
方法中通过try - catch
块处理任务内部可能抛出的异常,并记录异常信息。这样即使任务执行失败,线程池中的线程依然能够继续执行其他任务。