任务入参必须可序列化,应使用轻量级persistabletask类包装businessid、tasktype和json payload存入redis;拒绝策略中仅快速落库不阻塞,配合定时补偿机制(每15–30秒)拉取重试,失败达3次转入死信队列。

任务入参必须可序列化,且携带业务标识
直接把 Runnable 对象塞进 Redis 会失败——它通常不可序列化,还可能持有上下文、Spring Bean 等非静态引用。正确做法是:定义一个轻量级任务载体类(如 PersistableTask),只保留必要字段:businessId(如订单号)、taskType(如 “sms_notify”)、payload(JSON 字符串格式的业务参数)。提交任务时,必须用这个类包装原始逻辑,确保能安全转成字符串存入 Redis。
拒绝策略中只做快速落库,不阻塞也不重试
rejectedExecution 方法必须轻量、无耗时、不抛异常。关键步骤如下:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 先做空值和线程池状态校验:if (r == null || executor.isShutdown()) return;
- 强转为 PersistableTask,提取 payload 和 businessId;若类型不符,打告警日志后跳过
- 调用 redisTemplate.opsForList().leftPush("threadpool:overflow", taskJson),写入 Redis 列表
- 包裹 try-catch,写入失败时不 throw,仅记录 ERROR 日志 + 上报监控指标(如 redis.persist.fail.count)
Redis 队列需配合定时补偿机制才能真正“不丢”
存进去只是第一步,没人读就等于白存。必须配套一个独立的定时任务(如每 15–30 秒执行一次),负责从 Redis 拉取并重新提交:
- 使用 rightPop 或 brPop(带阻塞)从队列头拉出任务,避免并发重复消费
- 反序列化为 PersistableTask 后,调用线程池 execute() 提交;若再次被拒,按规则更新重试次数并写回 Redis(支持最多 3 次重试)
- 成功执行后,可选地记录完成日志或发埋点;失败达上限则转入死信队列(如 threadpool:dead:queue)并触发人工告警
注意内存与 Redis 的协同边界
如果用的是「内存队列 + Redis 溢出」混合队列(如自定义 PersistableTaskQueue),要明确溢出触发点:
- 内存队列(如 ArrayBlockingQueue(500))满时,才走 Redis 落库路径
- Redis 写入前建议加简单限流(如 RateLimiter),防突发打爆 Redis 连接数
- 生产环境 Redis Key 建议带业务前缀和时间分片(如 threadpool:overflow:202605),便于清理和监控










