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

Java 線程通信核心技術大全:join、wait/notify、CountDownLatch、CyclicBarrier、FutureTask 實戰詳解

     編輯:Java 相關知識

多線程協作是 Java 並發編程的核心課題。本文通過 5 個經典場景,系統講解 Thread.join()、Object.wait/notify、CountDownLatch、CyclicBarrier、FutureTask + Callable 等核心機制的原理、適用場景與代碼實戰,助你構建高效、可控的並發系統。

場景一:線程順序執行 — Thread.join()

需求:線程 B 等待線程 A 完全結束後再執行。

Thread A = new Thread(() -> printNumber("A"));
Thread B = new Thread(() -> {
    try { A.join(); } catch (InterruptedException e) { e.printStackTrace(); }
    printNumber("B");
});
B.start(); A.start(); // B 先啟動但會阻塞等待 A

原理:join() 內部調用 wait(0),當線程終止時 JVM 自動喚醒等待者。適用於簡單的串行依賴。

場景二:精細粒度交替執行 — Object.wait()/notify()

需求:A 印 1 → B 印 1,2,3 → A 印 2,3。

Object lock = new Object();
Thread A = new Thread(() -> {
    synchronized(lock) {
        System.out.println("A 1");
        lock.wait(); // 釋放鎖進入等待
        System.out.println("A 2"); System.out.println("A 3");
    }
});
Thread B = new Thread(() -> {
    synchronized(lock) {
        System.out.println("B 1"); System.out.println("B 2"); System.out.println("B 3");
        lock.notify(); // 喚醒 A
    }
});
A.start(); B.start();

關鍵點:

  • 共用同一把鎖 lock。
  • wait() 釋放鎖並進入 WAITING 狀態;notify() 喚醒一個等待線程(需重新競爭鎖)。
  • 必須在 synchronized 區塊內調用,否則拋 IllegalMonitorStateException。

場景三:一個線程等待多個線程完成 — CountDownLatch

需求:D 等待 A、B、C 全部結束(A/B/C 並行執行)。

CountDownLatch latch = new CountDownLatch(3); // 計數器初值 3
// D 線程
new Thread(() -> {
    latch.await(); // 阻塞直到計數歸零
    System.out.println("D start");
}).start();
// A/B/C 線程
for (char n : new char[]{'A','B','C'}) {
    new Thread(() -> {
        doWork(n);
        latch.countDown(); // 計數 -1
    }).start();
}

特點:一次性計數器,不可重置。適用於「主線程等待多個任務完成」或「多線程等待準備就緒」。

場景四:多線程互相等待,同步起跑 — CyclicBarrier

需求:三選手各自準備,全員就緒後同時起跑。

CyclicBarrier barrier = new CyclicBarrier(3); // 3 方參與
for (char n : new char[]{'A','B','C'}) {
    new Thread(() -> {
        prepare(n);
        barrier.await(); // 到達屏障等待
        run(n); // 所有人同時執行
    }).start();
}

對比 CountDownLatch:

特性CountDownLatchCyclicBarrier
可重用性不可重置可循環使用(reset())
等待邏輯一等多多等多(互相等待)
攔截動作無可選 barrierAction(所有方到達前執行)

場景五:子線程返回結果給主線程 — FutureTask + Callable

Runnable 無返回值,Callable<V> 支持泛型返回值與拋出異常。

Callable<Integer> task = () -> {
    int sum = 0;
    for (int i = 1; i <= 100; i++) sum += i;
    return sum;
};
FutureTask<Integer> future = new FutureTask<>(task);
new Thread(future).start();

System.out.println("主線程繼續做其他事...");
Integer result = future.get(); // 阻塞獲取結果
System.out.println("結果:" + result); // 5050

進階:生產環境建議配合 ExecutorService 線程池管理 Future,避免手動創建線程開銷,並可使用 CompletableFuture (Java 8+) 實現非阻塞回調組合。


總結選型指南

  • 簡單串行:Thread.join()
  • 雙線程精細協作:wait/notify(或 Lock + Condition 更靈活)
  • 一等多、一次性:CountDownLatch
  • 多等多、可循環:CyclicBarrier
  • 異步計算獲取結果:FutureTask/Callable → 升級 CompletableFuture

線程通信本質是「狀態協調與內存可見性」。掌握這些工具的適用邊界,能寫出既正確又高效的並發代碼。

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