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