MST
星途 面试题库

面试题:自定义Java线程池终止策略与优化

请你基于Java原生线程池,自定义一种终止策略,当线程池达到终止状态时,能够将未执行完的任务以特定格式(如JSON)持久化到本地文件系统,并对线程池执行任务过程中的资源使用情况进行详细的性能分析与优化建议,包括如何减少线程切换开销、提高任务队列处理效率等方面。请给出完整的代码实现思路和关键代码片段。
43.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

自定义终止策略思路

  1. 实现 RejectedExecutionHandler 接口:用于处理拒绝的任务,这里用于在任务被拒绝时准备持久化。
  2. 继承 ThreadPoolExecutor:重写 terminated 方法,在池终止时执行任务持久化操作。
  3. 性能分析:通过记录任务执行时间、线程活动时间等指标来分析资源使用情况。
  4. 优化建议:使用合适的队列类型、调整线程数、减少锁竞争等。

关键代码片段

  1. 自定义拒绝策略
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 这里可以对被拒绝的任务进行预处理,比如加入到待持久化列表
    }
}
  1. 自定义线程池并实现终止策略
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.google.gson.Gson;

public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
    private List<Runnable> unfinishedTasks = new ArrayList<>();

    public CustomThreadPoolExecutor(int corePoolSize,
                                    int maximumPoolSize,
                                    long keepAliveTime,
                                    TimeUnit unit,
                                    BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new CustomRejectedExecutionHandler());
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        // 可以在这里记录任务执行时间等性能指标
    }

    @Override
    protected void terminated() {
        Gson gson = new Gson();
        String json = gson.toJson(unfinishedTasks);
        try (FileWriter writer = new FileWriter("unfinished_tasks.json")) {
            writer.write(json);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void execute(Runnable task) {
        if (isShutdown()) {
            // 如果线程池已关闭,将任务加入待持久化列表
            unfinishedTasks.add(task);
        } else {
            super.execute(task);
        }
    }
}
  1. 性能分析与优化
  • 减少线程切换开销
    • 调整线程数:根据任务类型(CPU 密集型或 I/O 密集型)合理设置核心线程数和最大线程数。例如,CPU 密集型任务,核心线程数可设置为 CPU 核心数;I/O 密集型任务,可适当增加线程数。
    • 使用 ThreadLocal:避免多线程竞争共享资源,减少锁的使用,从而减少线程切换。
  • 提高任务队列处理效率
    • 选择合适的队列:对于有界任务,ArrayBlockingQueue 可以有效控制内存使用;对于无界任务,LinkedBlockingQueue 更合适。
    • 优化队列操作:尽量减少对任务队列的同步操作,避免不必要的锁竞争。例如,在任务入队和出队时,可以使用无锁数据结构(如 ConcurrentLinkedQueue)来提高效率。

使用示例

public class Main {
    public static void main(String[] args) {
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
        CustomThreadPoolExecutor executor = new CustomThreadPoolExecutor(
                2, 4, 10, TimeUnit.SECONDS, workQueue);

        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                // 模拟任务执行
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
                if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                    System.err.println("Pool did not terminate");
                }
            }
        } catch (InterruptedException ie) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

上述代码实现了一个自定义线程池,具备任务持久化到本地文件的终止策略,并给出了性能分析与优化建议。代码中使用了 Google 的 Gson 库来处理 JSON 序列化,实际应用中可以根据需要选择其他 JSON 处理库。