Java中让多个异步任务按顺序执行,核心是控制任务提交时机与依赖关系:单线程线程池最简单可靠;CompletableFuture适合有数据依赖的链式调用;CountDownLatch适用于线程级门控;BlockingQueue+单消费者提供高灵活性。

Java 中让多个异步任务按顺序依次执行,核心不是“强制线程排队”,而是控制任务的**提交时机与依赖关系**。单线程串行执行最简单可靠,但若需利用多线程又要求顺序,就得靠同步机制协调。下面几种方式覆盖常见场景:
用单线程线程池串行提交
最直接、无锁、不易出错的方式:把所有任务提交给一个 SingleThreadExecutor。它内部只维护一个工作线程,天然保证 FIFO 和顺序执行。
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> { System.out.println("任务1"); });
executor.submit(() -> { System.out.println("任务2"); });
executor.submit(() -> { System.out.println("任务3"); });
// 输出一定是:任务1 → 任务2 → 任务3
✅ 适合:逻辑上必须串行、无需并发、任务本身不阻塞线程(如纯计算或短IO)。
用 CompletableFuture 串联依赖
当任务有输入输出依赖(比如任务2需要任务1的结果),用 thenApply / thenCompose 链式调用,自动按序触发,底层可复用线程池。
立即学习“Java免费学习笔记(深入)”;
- 任务间有数据传递:用
thenApply(同步转换)或thenCompose(返回新 CompletableFuture) - 任务本身是异步的(如调用远程接口):确保每个 stage 返回的是
CompletableFuture - 避免在 lambda 里直接阻塞(如
join()),否则可能卡住线程池
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "result1", executor);
CompletableFuture<Integer> f2 = f1.thenApply(s -> s.length());
CompletableFuture<Void> f3 = f2.thenAccept(len -> System.out.println("长度:" + len));
用 CountDownLatch 或 CyclicBarrier 协调多线程顺序
适用于多个独立线程启动后,必须等前一个完成才能开始下一个——本质是“线程级门控”。
-
CountDownLatch(1)最常用:任务A执行完countDown(),任务B用await()等待 - 两个任务之间只需一次等待,别用
CyclicBarrier(适合循环屏障场景) - 注意异常时也要调用
countDown(),否则后续任务永久阻塞
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
System.out.println("任务1执行");
latch.countDown(); // 通知下一个
}).start();
new Thread(() -> {
try { latch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
System.out.println("任务2执行");
}).start();
用 BlockingQueue + 单消费者线程手动调度
灵活性最高:生产者(任意线程)将任务放入队列,单独一个消费者线程不断取任务并执行。可加优先级、重试、日志等扩展逻辑。
- 推荐
LinkedBlockingQueue或ArrayBlockingQueue - 消费者用
take()阻塞获取,确保不空转 - 适合需要统一监控、限流、失败重试的后台任务流
不复杂但容易忽略:顺序执行的关键不在“线程怎么跑”,而在于“谁决定下一个任务什么时候开始”。选对模型比手写 wait/notify 更安全稳定。


















