在Java中,线程池是通过java.util.concurrent包下的ThreadPoolExecutor实现的。虽然Executors工厂类可以快速得到常见的线程池,但它们往往隐藏了细节,难以满足对线程管理、拒绝策略、线程命名等细粒度控制的需求。下面通过一个完整的示例,演示如何从零开始构建一个自定义线程池,并对其进行性能调优。
1. 选择合适的核心参数
int corePoolSize = Runtime.getRuntime().availableProcessors(); // 核心线程数
int maximumPoolSize= corePoolSize * 2; // 最大线程数
long keepAliveTime = 60L; // 空闲线程存活时间
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue <Runnable> workQueue = new LinkedBlockingQueue<>(1000);
- 核心线程数:通常设为CPU核数,保证所有 CPU 能被充分利用。
- 最大线程数:根据业务峰值来决定。若任务主要是 IO,最大线程数可以更高。
- 阻塞队列:
LinkedBlockingQueue可指定容量。容量越小,任务积压越快,但也能更快触发拒绝策略。
2. 自定义线程工厂
ThreadFactory customThreadFactory = new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix = "CustomPool-Thread-";
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
};
- 给线程命名可以帮助日志定位。
- 可根据业务需要设置为守护线程、优先级等。
3. 拒绝策略
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
CallerRunsPolicy:当线程池满且队列也满时,将任务直接在调用线程中执行,起到“降级”效果,避免丢失任务。- 其它策略如
AbortPolicy、DiscardPolicy、DiscardOldestPolicy也可根据需要选择。
4. 构造 ThreadPoolExecutor
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
customThreadFactory,
handler
);
5. 使用示例
for (int i = 0; i < 2000; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " executing task " + taskId);
try {
Thread.sleep(500); // 模拟业务耗时
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
6. 监控与调优
- 核心/最大线程数:观察
Thread.activeCount()与Runtime.getRuntime().availableProcessors()的比值。 - 队列长度:
workQueue.size()越大说明任务积压严重。 - 线程空闲时间:
keepAliveTime可以动态调节,根据业务峰谷变化调整。 - JMX 监控:实现
java.lang.management.ThreadPoolExecutorMXBean接口,或使用java.util.concurrent.ThreadPoolExecutor的getActiveCount()、getQueue().size()等方法结合 JMX 监控。
7. 关闭线程池
executor.shutdown(); // 先不接受新任务,等待已提交任务完成
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 强制关闭
}
8. 小结
- 自定义线程池能让你精确控制线程创建、命名、优先级、拒绝策略等。
- 通过合理配置核心/最大线程数、队列容量以及拒绝策略,能够在高并发情况下保持系统稳定。
- 定期监控线程池状态,及时根据业务波动进行参数调整,是实现高可用 Java 并发程序的关键。
以上示例展示了从零开始搭建一个自定义线程池的完整过程,你可以根据具体业务场景进一步扩展,如加入线程池监控、任务优先级、动态扩容等功能。

发表回复