线程池默认不保证任务执行顺序;严格FIFO需单线程池+无界/足够容量阻塞队列;newSingleThreadExecutor最简单;手动构造时避免ArrayBlockingQueue容量过小和拒绝策略误用;分组有序可用ConcurrentHashMap+单线程池。
线程池默认不保证任务执行顺序
Java 的 ThreadPoolExecutor 本身不维护任务提交顺序与执行顺序的一致性——哪怕你用 newFixedThreadPool(1),只要任务在运行中被中断、拒绝或线程被复用,就可能出现看似“乱序”的现象。真正能约束顺序的,是任务提交方式 + 队列类型 + 线程数三者共同作用的结果。
关键判断点:如果你需要严格 FIFO(先提交先执行),必须满足两个条件:单线程池 + 无界/有界但不触发拒绝策略的阻塞队列;否则,多线程下天然存在竞争和调度不确定性。
用 newSingleThreadExecutor() 最简单实现顺序执行
这是最直接、副作用最少的方式。它内部封装了一个 FinalizableDelegatedExecutorService 包裹的单线程池,底层队列是 LinkedBlockingQueue(无界),天然 FIFO。
- 适合场景:日志写入、状态机流转、串行化外部 API 调用等对时序敏感且吞吐压力不大的任务
- 注意点:
shutdownNow()可能中断正在执行的任务,若需优雅终止,应配合awaitTermination()和任务自身可中断逻辑 - 不能用于 CPU 密集型长任务,否则会阻塞后续所有任务
自定义单线程池时别踩 ArrayBlockingQueue 容量陷阱
如果不用 newSingleThreadExecutor(),而是手动构造 ThreadPoolExecutor,常见错误是用小容量 ArrayBlockingQueue 却忽略拒绝策略:
立即学习“Java免费学习笔记(深入)”;