如何用Java ExecutorService实现线程内有序、整体并行的操作执行
问题分析与解决方案
你的代码无法达到预期效果的核心原因是:printA和printB仅仅是向线程池提交任务,线程池会并行调度这些任务,即便你在外部线程中先调用printA再调用printB,线程池中的A任务和B任务依然会交叉执行,无法保证同一逻辑单元内的A全部完成后再执行B。
下面提供两种可行的解决方案:
方案一:用CountDownLatch控制A任务全部完成后再执行B
这种方式保留了将A、B拆分为独立线程任务的逻辑,同时通过内部CountDownLatch确保所有A执行完毕后才提交B任务:
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(10); CountDownLatch outerLatch = new CountDownLatch(5); for (int i = 1; i <= 5; i++) { executorService.execute(() -> { try { // 提交所有A任务并等待完成 CountDownLatch aCompleteLatch = new CountDownLatch(5); for (int j = 0; j < 5; j++) { executorService.execute(() -> { System.out.println("A"); aCompleteLatch.countDown(); }); } aCompleteLatch.await(); // 阻塞直到所有A执行完毕 // 提交所有B任务 for (int j = 0; j < 5; j++) { executorService.execute(() -> { System.out.println("B"); }); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { outerLatch.countDown(); } }); } outerLatch.await(); executorService.shutdown(); if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { executorService.shutdownNow(); } } }
方案二:在当前线程顺序执行A、B打印
如果不需要将A、B拆分为独立线程任务,直接在每个外层线程中先打印所有A,再打印所有B,逻辑更简洁:
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(10); CountDownLatch countDownLatch = new CountDownLatch(5); for (int i = 1; i <= 5; i++) { executorService.execute(() -> { try { // 连续打印5个A for (int j = 0; j < 5; j++) { System.out.println("A"); } // 连续打印5个B for (int j = 0; j < 5; j++) { System.out.println("B"); } } finally { countDownLatch.countDown(); } }); } countDownLatch.await(); executorService.shutdown(); if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { executorService.shutdownNow(); } } }
两种方案都能保证每个逻辑单元内的printB相关操作在printA全部完成后执行,同时外层的5个任务依然保持并行执行的特性。
内容的提问来源于stack exchange,提问作者Pushpak
相关产品推荐
相关产品推荐

