首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 多線程通信三大核心模式:while 輪詢、wait/notify、CountDownLatch 實戰對比

     編輯:Java 綜合教學

Java 多線程通信三大核心模式實戰對比

線程間通信是併發編程核心難點。本文通過同一生產者-消費者場景,實戰對比 while 輪詢、wait/notify、CountDownLatch 三種模式的代碼實現、CPU 開銷、適用場景、避坑指南。

一、場景定義:列表達到 5 個元素通知消費者停止

// 共享數據結構
List list = new ArrayList<>();
// 生產者:每 500ms 添加 1 個元素,共 10 個
// 消費者:監聽 size==5 時停止並拋異常模擬業務終止

二、模式一:while 死循環輪詢 (最原始、最費 CPU)

// 消費者線程
while (true) {
    if (list.size() == 5) {
        System.out.println("收到通知,停止");
        throw new RuntimeException();
    }
    // 缺失 sleep → 100% CPU 空轉
    // 加 sleep → 延遲響應、難以精確控制
}
  • 缺點:忙等待消耗 CPU、響應延遲不可控、無法釋放鎖
  • 唯一優點:無需同步機制,極簡場景可用
  • 結論:生產環境禁用

三、模式二:wait/notify (Object 監視器模式,JDK 1.0+)

final Object lock = new Object();

// 生產者
synchronized (lock) {
    for (int i=0; i<10; i++) {
        list.add("item");
        if (list.size() == 5) {
            lock.notify(); // 喚醒一個等待線程,不釋放鎖
        }
        Thread.sleep(500);
    }
}

// 消費者 (必須先執行獲取鎖)
synchronized (lock) {
    if (list.size() != 5) {
        lock.wait(); // 釋放鎖,進入 WAITING 狀態
    }
    System.out.println("收到通知,停止");
    throw new RuntimeException();
}

關鍵規則 (必背)

  1. 必須在 synchronized 塊中調用,否則 IllegalMonitorStateException
  2. wait() 釋放鎖,notify() 不放鎖 (需退出 synchronized 塊)
  3. 虛假喚醒:需用 while (condition) wait() 而非 if
  4. notifyAll() vs notify():多消費者場景必須 notifyAll() 避免信號丟失

優缺點

  • 優點:標準 API、無第三方依賴、精確控制
  • 缺點:API 低級、易死鎖、代碼啰嗦、需手動管理鎖狀態

四、模式三:CountDownLatch (JUC 同步器,JDK 1.5+)

final CountDownLatch latch = new CountDownLatch(1); // 計數器初始 1

// 生產者
for (int i=0; i<10; i++) {
    list.add("item");
    if (list.size() == 5) {
        latch.countDown(); // 計數器 -1,歸零釋放所有 await
    }
    Thread.sleep(500);
}

// 消費者
if (list.size() != 5) {
    latch.await(); // 阻塞直到計數器為 0
}
System.out.println("收到通知,停止");
throw new RuntimeException();

核心特性

  • 一次性:計數器歸零不可重置,不適用重複通信
  • 無需鎖管理:內部用 AQS 實現,線程安全
  • 支持超時:await(5, TimeUnit.SECONDS) 防死等

五、擴展:更強大的 JUC 同步工具

工具核心能力適用場景
CyclicBarrier可重置的計數器,攔截點攔住所有線程多線程分階段計算、並行測試
Phaser動態註冊/取消註冊、分階段同步動態參與者數量的多階段任務
Semaphore許可證控制並發訪問數資源池限流、連接池
Exchanger雙線程數據交換生產者-消費者雙緩衝交換
CompletableFuture異步組合、回調地獄終結者現代異步編程首選

六、選型決策表

場景推薦方案理由
單次事件通知 (啟動、關閉、就緒)CountDownLatch語義清晰、無鎖煩惱、支持超時
循環/重複的生產者-消費者BlockingQueue / ArrayBlockingQueue內置阻塞、無需手動同步、JUC 標準
多線程分階段同步等待CyclicBarrier / Phaser支持重置/動態參與者
低級鎖優化、非阻塞算法wait/notify / LockSupport極致性能、框架開發
現代業務異步編排CompletableFuture / Reactor / RxJava聲明式、組合式、異常傳播完善

七、最佳實踐總結

  1. 優先用高級併發工具 (JUC):BlockingQueue、CompletableFuture、CountDownLatch,減少手寫同步
  2. wait/notify 僅用於框架/基礎設施代碼:業務代碼禁用
  3. while 輪詢嚴禁進生產:哪怕加 sleep 也是反模式
  4. 共享可變狀態最小化:用不可變對象、ThreadLocal、Actor 模型
  5. 測試併發代碼:用 jcstress、ConcurrencyTestRunner、壓測驗證

線程通信本質是內存可見性 + 阻塞喚醒。掌握 JUC 同步器工具箱,拋棄底層 wait/notify,是寫出正確、高效、可維護併發代碼的捷徑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved