天空大作战
94.86M · 2026-02-04
自定义拒绝策略的核心是实现java.util.concurrent.RejectedExecutionHandler接口,重写唯一的rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法:
r:被线程池拒绝的任务实例;executor:当前线程池实例,可通过它获取实时运行状态(活跃线程数、队列任务数、完成任务数等),用于问题排查。import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义拒绝策略Demo:详细日志+线程池状态监控
*/
public class CustomRejectPolicyDemo {
// 1. 实现RejectedExecutionHandler,自定义拒绝策略
static class MyCustomRejectPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 核心:打印详细拒绝日志 + 线程池实时状态(生产级排查必备)
String rejectLog = String.format(
"===== 任务被拒绝 =====n" +
"拒绝时间:%sn" +
"被拒任务:%sn" +
"线程池状态:运行中=%s | 核心线程数=%d | 最大线程数=%dn" +
"当前状态:活跃线程数=%d | 队列任务数=%d | 已完成任务数=%d | 总任务数=%d",
System.currentTimeMillis(),
r.toString(),
executor.isRunning(), // 线程池是否处于RUNNING状态
executor.getCorePoolSize(),
executor.getMaximumPoolSize(),
executor.getActiveCount(), // 实时活跃线程数
executor.getQueue().size(), // 队列中等待的任务数
executor.getCompletedTaskCount(), // 已完成的任务总数
executor.getTaskCount() // 提交的总任务数(完成+执行中+队列中)
);
// 实际生产中可替换为SLF4J/Logback日志框架
System.err.println(rejectLog);
// 可选:根据业务需求扩展(如任务持久化到MQ/Redis、触发限流告警、主线程兜底执行等)
}
}
// 2. 自定义线程工厂(可选,用于设置线程名,便于排查任务执行线程)
static class MyThreadFactory implements ThreadFactory {
private final AtomicInteger threadId = new AtomicInteger(1);
private final String threadPrefix = "biz-worker-thread-";
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, threadPrefix + threadId.getAndIncrement());
thread.setDaemon(false); // 非守护线程,保证任务执行完成
thread.setPriority(Thread.NORM_PRIORITY); // 正常优先级
return thread;
}
}
// 主程序:测试自定义拒绝策略
public static void main(String[] args) throws InterruptedException {
// 线程池核心参数:故意设置小参数,方便触发拒绝策略
int corePoolSize = 2; // 核心线程数
int maximumPoolSize = 4; // 最大线程数
long keepAliveTime = 1; // 非核心线程空闲超时时间
int queueCapacity = 2; // 任务队列容量(有限队列,必选,否则无法触发拒绝策略)
// 3. 创建线程池,指定【自定义拒绝策略】
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(queueCapacity), // 有限容量队列,触发拒绝策略的关键
new MyThreadFactory(), // 自定义线程工厂(可选)
new MyCustomRejectPolicy() // 核心:指定自定义拒绝策略
);
try {
// 提交7个任务,触发拒绝策略(2核心+2队列+2非核心=6,第7个任务被拒绝)
for (int i = 1; i <= 7; i++) {
int taskId = i;
executor.submit(() -> {
try {
// 模拟任务执行耗时1秒
TimeUnit.SECONDS.sleep(1);
System.out.printf("任务%d执行成功,执行线程:%s%n", taskId, Thread.currentThread().getName());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.printf("任务%d被中断%n", taskId);
}
});
System.out.printf("任务%d已提交%n", taskId);
}
} finally {
// 4. 优雅关闭线程池(必须,避免资源泄漏)
executor.shutdown();
// 等待线程池终止,超时则强制关闭
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
}
}
本次线程池参数设置为核心2+最大4+队列2,总处理能力 = 6(2 核心线程执行 + 2 队列等待 + 2 非核心线程执行),提交第 7 个任务时,满足任务队列已满 + 线程数达到 maximumPoolSize,触发自定义拒绝策略。
任务1已提交
任务2已提交
任务3已提交
任务4已提交
任务5已提交
任务6已提交
任务7已提交
===== 任务被拒绝 =====
拒绝时间:1738456200000
被拒任务:java.util.concurrent.FutureTask@1b6d3586
线程池状态:运行中=true | 核心线程数=2 | 最大线程数=4
当前状态:活跃线程数=4 | 队列任务数=2 | 已完成任务数=0 | 总任务数=7
任务1执行成功,执行线程:biz-worker-thread-1
任务2执行成功,执行线程:biz-worker-thread-2
任务3执行成功,执行线程:biz-worker-thread-3
任务4执行成功,执行线程:biz-worker-thread-4
任务5执行成功,执行线程:biz-worker-thread-1
任务6执行成功,执行线程:biz-worker-thread-2
RejectedExecutionHandler接口,重写rejectedExecution方法;maximumPoolSize;ThreadPoolExecutor实例可获取全量运行状态,是生产排查任务拒绝问题的关键;shutdown()+awaitTermination()),避免资源泄漏。