Java 执行器与线程池

Executor 框架如何提交任务、管理线程池与关闭:队列、拒绝策略与生命周期。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java 执行器与线程池

这个概念为什么出现

直接 new Thread 无法统一限流、复用与关闭。ExecutorService 把任务提交与执行策略分离:固定/弹性线程池、队列、拒绝策略与 Future 结果。

[!abstract] 一句话理解 线程池复用工作线程执行提交的任务;必须正确配置队列与拒绝策略,并在关闭时 shutdown/awaitTermination

最小可运行示例

场景:图片缩略图任务有限并发

import java.util.concurrent.*;

public class ThumbPool {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = Executors.newFixedThreadPool(2, r -> {
            Thread t = new Thread(r);
            t.setName("thumb-" + t.getId());
            return t;
        });
        try {
            Future<String> f = pool.submit(() -> {
                // 模拟生成缩略图
                return "thumb-ok";
            });
            System.out.println(f.get(1, TimeUnit.SECONDS));
        } finally {
            pool.shutdown();
            pool.awaitTermination(1, TimeUnit.SECONDS);
        }
    }
}

建议运行:

javac ThumbPool.java && java ThumbPool

期望输出:

thumb-ok

结合场景再看三个关注点

  1. submit 返回 Future 可取结果/异常。
  2. shutdown 在 finally,防泄漏。
  3. 工厂方法要懂默认队列newFixedThreadPool 用无界队列,压力下可能 OOM。

核心概念与准确模型

1. 关键角色

  • Executor / ExecutorService
  • ThreadPoolExecutor 核心实现
  • 工作队列、核心/最大线程、拒绝策略

2. 拒绝策略

Abort / CallerRuns / Discard / DiscardOldest 等

3. 生命周期

shutdown 温和停 → awaitTermination → 必要时 shutdownNow

4. Callable vs Runnable

  • Callable 有返回值且可抛受检异常

边界情况与反直觉行为

  1. get() 无限等。
  2. 池线程吞掉异常(Future 中持有)。
  3. 错误的最大线程 + 无界队列 = 实际不扩容。

常见误区

[!warning] 常见误区:Executors 工厂无脑用 生产常显式 ThreadPoolExecutor 并命名、监控队列长度。

工程实践

  1. 按业务隔离池(CPU 密集 vs IO)。
  2. 监控活跃线程、队列、拒绝次数。
  3. 请求上下文传递(MDC)要包装任务。
  4. 与虚拟线程:大量阻塞任务可用新模型(见虚拟线程篇)。

本节总结

  • 池化执行是默认工程姿势
  • 配置队列/拒绝/关闭
  • Future 承载结果与错误

自测题

  1. shutdown 与 shutdownNow 区别?
  2. 无界队列的主要风险?
参考答案
  1. 前者不再接新任务并执行完在途;后者尝试中断在途并返回等待任务。
  2. 任务堆积导致内存膨胀,线程数可能不按预期增长。

延伸阅读与资料来源

资料类型支撑内容
Executor interfaceAPI执行器
ThreadPoolExecutorAPI池参数
创建于 2026/7/15 更新于 2026/7/15