Java子線程如何優(yōu)雅地通知主線程任務(wù)完成?
高效的多線程編程需要子線程在任務(wù)完成后通知主線程。本文介紹兩種常用的方法:CompletableFuture 和 CountDownLatch,并著重強調(diào)線程安全和最佳實踐。
方法一:使用 CompletableFuture
CompletableFuture 提供了一種簡潔的方式來處理異步操作,并方便地等待多個子線程完成。CompletableFuture.allOf() 方法可以等待所有給定的 CompletableFuture 對象完成。
立即學(xué)習(xí)“Java免費學(xué)習(xí)筆記(深入)”;
代碼示例:
List<CompletableFuture<?>> futures = new ArrayList<>(); // 創(chuàng)建并啟動子線程 for (int i = 0; i < 2; i++) { futures.add(CompletableFuture.runAsync(() -> { // 模擬子線程任務(wù) System.out.println("子線程 " + i + " 執(zhí)行完成"); })); } // 等待所有子線程完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 主線程處理數(shù)據(jù) System.out.println("所有子線程執(zhí)行完成,開始處理數(shù)據(jù)"); }
方法二:使用 CountDownLatch
CountDownLatch 是一種同步工具類,可以用來等待一組事件的完成。初始化時設(shè)置計數(shù)器,每個子線程完成任務(wù)后調(diào)用 countDown() 方法將計數(shù)器減一,主線程調(diào)用 await() 方法等待計數(shù)器變?yōu)榱恪?/p>
代碼示例:
final CountDownLatch latch = new CountDownLatch(2); // 初始化計數(shù)器為 2 // 創(chuàng)建并啟動子線程 for (int i = 0; i < 2; i++) { new Thread(() -> { // 模擬子線程任務(wù) System.out.println("子線程 " + i + " 執(zhí)行完成"); latch.countDown(); // 計數(shù)器減 1 }).start(); } // 主線程等待子線程完成 try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 主線程處理數(shù)據(jù) System.out.println("所有子線程執(zhí)行完成,開始處理數(shù)據(jù)"); }
重要提示:
- 線程安全: ArrayList 不是線程安全的。在并發(fā)環(huán)境下,建議使用 CopyOnWriteArrayList 來替代,以避免數(shù)據(jù)競爭。 如果需要在子線程中修改共享變量,則必須使用合適的同步機制,例如 volatile 關(guān)鍵字或鎖機制,以確保線程安全。
- 異常處理: 在實際應(yīng)用中,需要完善的異常處理機制,以捕獲并處理子線程中可能發(fā)生的異常。 CompletableFuture 提供了 exceptionally() 方法來處理異常。 CountDownLatch 需要在 await() 方法中捕獲 InterruptedException。
選擇哪種方法取決于具體的應(yīng)用場景。CompletableFuture 更適用于需要處理異步結(jié)果的情況,而 CountDownLatch 更適用于簡單的等待多個線程完成的情況。 記住始終優(yōu)先考慮線程安全和健壯的異常處理。
? 版權(quán)聲明
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載。
THE END