MST

星途 面试题库

面试题:设计一个健壮的Java线程池异常处理策略

假设你正在开发一个高并发的应用,使用Java线程池执行大量不同类型的任务。请设计一个全面且健壮的异常处理策略,不仅要考虑任务执行时的各种异常情况,还要保证线程池在出现异常后能够尽可能地继续正常工作,同时能记录异常信息便于后续排查问题,描述策略并给出关键代码片段。
18.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

异常处理策略

  1. 任务执行异常处理:使用Thread.UncaughtExceptionHandler来捕获线程池线程执行任务时未捕获的异常。这样可以确保即使任务抛出异常,线程池中的线程不会直接终止,线程池能够继续正常工作。
  2. 记录异常信息:在UncaughtExceptionHandler中,使用日志框架(如log4jslf4j)记录详细的异常信息,包括异常类型、堆栈跟踪等,以便后续排查问题。
  3. 自定义任务包装类:为了更好地控制任务执行过程,特别是对于不同类型任务的异常处理,可以创建一个自定义的任务包装类,在其中添加特定于任务的异常处理逻辑。

关键代码片段

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块处理任务内部可能抛出的异常,并记录异常信息。这样即使任务执行失败,线程池中的线程依然能够继续执行其他任务。