Java 线程池

上一篇:Atomic 与 CAS · 下一篇:并发工具类

为什么用线程池#

new Thread().start() 每次创建/销毁线程开销大,线程过多耗尽 CPU/内存并加剧 GC。线程池 复用 工作线程,控制并发度。

ThreadPoolExecutor 七大参数#

ThreadPoolExecutor pool = new ThreadPoolExecutor(
2, // corePoolSize 核心线程数
4, // maximumPoolSize 最大线程数
60L, TimeUnit.SECONDS, // keepAliveTime 非核心空闲存活时间
new ArrayBlockingQueue<>(100), // workQueue 任务队列
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy() // handler 拒绝策略
);

执行流程#

  1. 线程数 < core → 新建核心线程执行
  2. 否则任务入队
  3. 队列满且线程数 < max → 新建非核心线程
  4. 队列满且线程数 = max → 拒绝策略

队列已满时#

  • 无界队列(如 LinkedBlockingQueue 默认 Integer.MAX_VALUE):任务排队,一般不新建超过 core 的线程(Fixed 例外看参数)
  • 有界队列(如 ArrayBlockingQueue):满则扩线程到 max,再满则拒绝

四种 Executors(了解即可,生产推荐手动 ThreadPoolExecutor)#

方法特点
newFixedThreadPool固定线程数,无界 LinkedBlockingQueue
newCachedThreadPool可扩缩,SynchronousQueue,线程多时可风险
newSingleThreadExecutor单线程顺序执行
newScheduledThreadPool定时/周期任务

阿里规范建议:不用 Executors 创建,明确队列边界与拒绝策略。

线程池状态#

RUNNING → SHUTDOWN(不接新任务,处理队列)→ STOP → TIDYING → TERMINATED

shutdown() 优雅关闭;shutdownNow() 尝试中断并返回未执行任务。

submit vs execute#

executesubmit
返回值voidFuture
异常线程 uncaught可通过 Future.get() 获取

拒绝策略#

AbortPolicy(抛异常)、CallerRunsPolicy(调用者线程跑)、DiscardPolicyDiscardOldestPolicy

合理线程数#

  • CPU 密集:约 CPU 核数 + 1
  • IO 密集:线程常阻塞,可 2 * CPU 核数 或按等待比例估算

公式直觉:等待时间占比越高,线程数可越多。

自定义线程池示例#

ExecutorService es = new ThreadPoolExecutor(
4, 8, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(200),
r -> {
Thread t = new Thread(r);
t.setName("biz-pool-" + t.getId());
return t;
},
new ThreadPoolExecutor.CallerRunsPolicy()
);

Fork/Join(预览)#

大任务拆小任务并行,再合并结果;注意拆分过深导致线程堆积。详见 并发工具类

一句话总结#

生产用 ThreadPoolExecutor 显式配置 core/max/有界队列/拒绝策略;IO 与 CPU 场景线程数估算不同。

文章目录

文章目录