← [ BACK_TO_NOTES ]

Java 执行器与线程池

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

#concept #growing #dev #java

[!info] related notes

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();
            try {
                if (!pool.awaitTermination(1, TimeUnit.SECONDS)) {
                    pool.shutdownNow();
                    if (!pool.awaitTermination(1, TimeUnit.SECONDS)) {
                        System.err.println("pool still running: tasks must cooperate with cancellation");
                    }
                }
            } catch (InterruptedException e) {
                pool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}

建议运行:

javac ThumbPool.java && java ThumbPool

期望输出:

thumb-ok

结合场景再看三个关注点

  1. submit 返回 Future 可取结果/异常。
  2. 在 finally 中启动关闭并检查等待结果;任务若不响应中断,即使 shutdownNow 也不保证退出。\
  3. 工厂方法要懂默认队列:newFixedThreadPool 用无界队列,压力下可能 OOM。

核心概念与准确模型

1. 关键角色

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

2. 拒绝策略

Abort 抛 RejectedExecutionException;CallerRuns 在提交线程执行(关闭后丢弃),会把负载反馈给调用方;Discard/DiscardOldest 可能静默丢任务。若调用方依赖 Future,静默丢弃可能让它永久等待,必须明确拒绝与结果契约。

3. 生命周期

shutdown 拒绝新任务但保留已提交任务(含队列);awaitTermination 只等待并返回是否已终止;shutdownNow 尝试中断运行中任务并返回未启动任务,不等待终止,也不保证返回任务的 Future 自动变成 cancelled。

4. Callable vs Runnable

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

边界情况与反直觉行为

  1. get() 可无限等;get(timeout) 只限制本次等待,超时不取消任务。取消需显式 cancel(true),而停止运行仍依赖任务响应中断。\
  2. submit 捕获任务异常到 Future,get 时通常包装为 ExecutionException;未观察 Future 会漏报。execute 的未捕获异常路径不同,可到达线程的异常处理器。\
  3. 错误的最大线程 + 无界队列 = 实际不扩容。

常见误区

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

工程实践

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

本节总结

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

自测题

  1. shutdown 与 shutdownNow 区别?
  2. 无界队列的主要风险?
参考答案
  1. shutdown 拒绝新任务,继续处理已提交任务;shutdownNow 尝试中断执行中的任务并返回未启动任务,两者都不是“已终止”的证明。\
  2. 任务堆积导致内存膨胀,线程数可能不按预期增长。

延伸阅读与资料来源

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

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本