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

Java 多線程通信核心:wait/notify 等待喚醒機制實現生產者消費者模式

     編輯:Java 綜合教學

Java 多線程通信核心:wait/notify 等待喚醒機制實現生產者消費者模式

多線程操作共享資源時,需協調執行順序。Java 提供 wait()、notify()、notifyAll() 實現線程間通信,必須在 同步塊 中調用,且鎖對象必須一致。

核心規則

  • wait():釋放鎖,進入等待隊列(等待池)
  • notify():喚醒一個等待線程,進入鎖池競爭鎖
  • notifyAll():喚醒所有等待線程
  • 這些方法定義在 Object 中,因為鎖屬於對象

經典案例:輸入/輸出線程交替打印

共享對象 People 包含姓名、性別與標記位 myLock。輸入線程寫入,輸出線程讀取,通過 wait/notify 實現嚴格交替。

完整代碼實現

/** 共享資源對象 */
class People {
    String name;
    String sex;
    boolean myLock = false; // false: 可寫入,true: 可讀取
}

/** 生產者:輸入線程 */
class PeopleJoin implements Runnable {
    private People resource;
    
    public PeopleJoin(People resource) { this.resource = resource; }
    
    @Override
    public void run() {
        boolean flag = true;
        while (true) {
            synchronized (resource) { // 必須同步於共享對象
                // 等待條件:資源被佔用(myLock=true)
                if (resource.myLock) {
                    try { resource.wait(); } 
                    catch (InterruptedException e) { e.printStackTrace(); }
                }
                
                // 寫入數據
                if (flag) {
                    resource.name = "taoshihan";
                    resource.sex = "nan";
                } else {
                    resource.name = "陶士涵";
                    resource.sex = "男";
                }
                flag = !flag;
                
                // 狀態翻轉,喚醒消費者
                resource.myLock = true;
                resource.notify();
            }
        }
    }
}

/** 消費者:輸出線程 */
class PeopleOut implements Runnable {
    private People resource;
    
    public PeopleOut(People resource) { this.resource = resource; }
    
    @Override
    public void run() {
        while (true) {
            synchronized (resource) {
                // 等待條件:資源未就緒(myLock=false)
                if (!resource.myLock) {
                    try { resource.wait(); } 
                    catch (InterruptedException e) { e.printStackTrace(); }
                }
                
                // 讀取並打印
                System.out.println(resource.name + "=====" + resource.sex);
                
                // 狀態翻轉,喚醒生產者
                resource.myLock = false;
                resource.notify();
            }
        }
    }
}

/** 測試啟動 */
public class ThreadDemo {
    public static void main(String[] args) {
        People resource = new People();
        new Thread(new PeopleJoin(resource)).start();
        new Thread(new PeopleOut(resource)).start();
    }
}

運行效果

多線程交替輸出截圖

控制台交替輸出英文與中文姓名性別,驗證協作正確。

關鍵注意事項

  1. 同步鎖一致性:生產者/消費者必須 synchronized(resource) 同一把鎖
  2. 條件判斷用 while 不用 if:防止虛假喚醒(JVM 規範允許無通知喚醒)
  3. 狀態變更後立即 notify:確保另一方能及時感知
  4. 現代替代方案:java.util.concurrent 包提供 BlockingQueue、CountDownLatch、Semaphore 等更高級協作工具,實際開發優先考慮

進階思考

此模式是「單生產單消費、單緩衝槽」模型。擴展為多生產多消費、有界緩衝區時,建議直接使用 ArrayBlockingQueue 等現成組件,避免手動管理鎖與條件的錯誤風險。

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