MST

星途 面试题库

面试题:自定义Java线程池饱和策略的设计与实现

请设计并实现一个自定义的Java线程池饱和策略,该策略需要在达到饱和时,优先将任务存入一个基于内存的队列(例如LinkedBlockingQueue),当内存队列也满时,将任务持久化到磁盘(假设使用文件系统),并且能够在系统资源允许时,从磁盘恢复任务继续执行。请给出详细的代码实现及必要的注释说明。
45.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
import java.io.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    // 基于内存的队列
    private final BlockingQueue<Runnable> memoryQueue;
    // 磁盘存储目录
    private final File diskDir;

    public CustomRejectedExecutionHandler(int memoryQueueCapacity, String diskDirPath) {
        memoryQueue = new LinkedBlockingQueue<>(memoryQueueCapacity);
        diskDir = new File(diskDirPath);
        if (!diskDir.exists()) {
            diskDir.mkdirs();
        }
    }

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 优先存入内存队列
        if (!memoryQueue.offer(r)) {
            // 内存队列满,持久化到磁盘
            File taskFile = new File(diskDir, System.currentTimeMillis() + ".task");
            try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(taskFile))) {
                oos.writeObject(r);
            } catch (IOException e) {
                throw new RuntimeException("Failed to persist task to disk", e);
            }
        }
    }

    // 从磁盘恢复任务的方法
    public void restoreTasks() {
        for (File taskFile : diskDir.listFiles()) {
            if (taskFile.isFile() && taskFile.getName().endsWith(".task")) {
                try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(taskFile))) {
                    Runnable task = (Runnable) ois.readObject();
                    // 这里可以将恢复的任务重新提交到线程池
                    // 假设存在一个名为executor的线程池
                    // executor.submit(task);
                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                } finally {
                    taskFile.delete();
                }
            }
        }
    }
}

在上述代码中:

  1. CustomRejectedExecutionHandler 类实现了 RejectedExecutionHandler 接口,该接口定义了线程池饱和时的处理逻辑。
  2. 构造函数接收两个参数,memoryQueueCapacity 用于指定内存队列的容量,diskDirPath 用于指定磁盘存储任务的目录。
  3. rejectedExecution 方法在任务被拒绝时调用,先尝试将任务放入内存队列 memoryQueue,如果内存队列已满,则将任务持久化到磁盘。
  4. restoreTasks 方法用于从磁盘恢复任务,遍历指定目录下的所有任务文件,将其反序列化后得到任务,这里注释部分给出了重新提交到线程池的示例(实际使用时需替换 executor 为真实的线程池实例),并在恢复后删除任务文件。