在自定义线程池拒绝策略时,要保证任务不丢失,核心思路是:将被拒绝的任务进行可靠持久化存储,并通过后续机制(如定时重试、手动触发)重新提交执行。具体实现需结合 “持久化方式”“重试机制” 和 “异常处理”,以下是详细方案:
一、核心实现原则
- 可靠持久化:将被拒绝的任务写入持久化介质(数据库、消息队列、磁盘文件等),确保进程重启后任务不丢失。
- 避免阻塞:持久化操作应尽可能异步或快速,避免阻塞提交任务的线程(如主线程)。
- 状态追踪:记录任务的状态(如 “待重试”“已完成”“失败”),避免重复执行或遗漏。
- 异常兜底:对持久化过程中可能出现的异常(如数据库连接失败)做兜底处理(如临时缓存到内存队列,后续重试)。
二、具体实现方案(附代码示例)
方案 1:持久化到数据库(适合核心任务,需事务保障)
将被拒绝的任务存入数据库 “任务表”,后续通过定时任务扫描表中 “待执行” 任务重新提交。
步骤 1:定义任务实体类和数据库表
// 任务实体类
public class RejectedTask {
private String id; // 任务唯一标识(UUID)
private String taskData; // 任务内容(可序列化任务对象)
private int retryCount; // 已重试次数
private String status; // 状态:WAITING(待执行)、SUCCESS(成功)、FAILED(失败)
private LocalDateTime createTime; // 创建时间
// getter/setter/构造方法
}
// 数据库表结构(MySQL示例)
/*
CREATE TABLE rejected_tasks (
id VARCHAR(36) PRIMARY KEY,
task_data TEXT NOT NULL,
retry_count INT DEFAULT 0,
status VARCHAR(20) NOT NULL,
create_time DATETIME NOT NULL
);
*/
步骤 2:实现自定义拒绝策略(保存任务到数据库)
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.UUID;
public class DbPersistenceRejectPolicy implements RejectedExecutionHandler {
private final TaskRepository taskRepository; // 数据库操作接口(需注入实现)
public DbPersistenceRejectPolicy(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// 1. 序列化任务(假设任务可序列化,或提取关键数据)
String taskData = serializeTask(r); // 自定义序列化逻辑(如JSON)
// 2. 创建任务记录
RejectedTask task = new RejectedTask(
UUID.randomUUID().toString(),
taskData,
0,
"WAITING",
LocalDateTime.now()
);
// 3. 存入数据库(带事务,确保保存成功)
taskRepository.save(task);
System.out.println("任务已持久化到数据库,ID:" + task.getId());
} catch (Exception e) {
// 兜底:若数据库保存失败,临时缓存到内存队列(需定期重试)
EmergencyTaskQueue

最低0.47元/天 解锁文章
1145

被折叠的 条评论
为什么被折叠?



