在多線程編程中,主線程常常需要等待多個子線程完成任務(wù)后才能繼續(xù)執(zhí)行后續(xù)操作。本文介紹兩種常用的方法:CompletableFuture.allOf 和 CountDownLatch,來優(yōu)雅地解決這個問題。
方法一:使用 CompletableFuture.allOf
CompletableFuture.allOf 方法接收多個 CompletableFuture 對象作為參數(shù),并返回一個新的 CompletableFuture。只有當所有輸入的 CompletableFuture 都完成時,這個新的 CompletableFuture 才會完成。
立即學習“Java免費學習筆記(深入)”;
示例代碼:
CompletableFuture<Void> futureA = CompletableFuture.runAsync(() -> { // 子線程 A 的任務(wù) }); CompletableFuture<Void> futureB = CompletableFuture.runAsync(() -> { // 子線程 B 的任務(wù) }); CompletableFuture<Void> allDone = CompletableFuture.allOf(futureA, futureB); allDone.thenRun(() -> { // 所有子線程都執(zhí)行完畢后執(zhí)行此代碼 // 處理共享數(shù)據(jù) });
方法二:使用 CountDownLatch
CountDownLatch 是一個計數(shù)器,可以用來同步多個線程。主線程調(diào)用 await() 方法等待計數(shù)器減為 0,而子線程完成任務(wù)后調(diào)用 countDown() 方法將計數(shù)器減 1。
示例代碼:
CountDownLatch latch = new CountDownLatch(2); // 初始化計數(shù)器為 2 (兩個子線程) Thread threadA = new Thread(() -> { // 子線程 A 的任務(wù) latch.countDown(); // 計數(shù)器減 1 }); Thread threadB = new Thread(() -> { // 子線程 B 的任務(wù) latch.countDown(); // 計數(shù)器減 1 }); threadA.start(); threadB.start(); try { latch.await(); // 主線程等待計數(shù)器減為 0 } catch (InterruptedException e) { e.printStackTrace(); } // 所有子線程都執(zhí)行完畢后執(zhí)行此代碼 // 處理共享數(shù)據(jù)
線程安全與共享變量
如果主線程和子線程需要共享數(shù)據(jù)(例如 ArrayList),必須確保數(shù)據(jù)訪問的線程安全。ArrayList 不是線程安全的,建議使用線程安全的替代方案,例如 ConcurrentHashMap 或 CopyOnWriteArrayList。
選擇哪種方法取決于具體場景。CompletableFuture 更適用于基于異步操作的場景,而 CountDownLatch 更適用于需要精確控制線程同步的場景。 兩種方法都能有效地解決主線程等待子線程完成的問題,確保程序的正確性和穩(wěn)定性。