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

Java 線程通信核心:wait/notify/notifyAll 深度解析與生產消費者實戰

     編輯:Java 程式設計入門

wait()、notify()、notifyAll() 是 Object 基類方法,而非 Thread 方法。每個對象天然擁有監視器鎖,這三個方法正是操作該鎖的核心 API。

核心規則

  • 同步前提:只能在 synchronized(obj) 塊內調用,即持有對象鎖的線程才能調用
  • wait():釋放鎖,進入等待隊列,直到被 notify/notifyAll 喚醒或中斷;喚醒後需重新獲取鎖才能繼續
  • notify():隨機喚醒一個等待線程,喚醒線程進入鎖池競爭鎖
  • notifyAll():喚醒所有等待線程,全部進入鎖池競爭
  • 虛假喚醒:wait() 應放在 while(condition) 循環中,防止無條件喚醒

經典生產者-消費者模式實戰

共享容器


public class Container {
    private final List<Object> list = new ArrayList<>();
    private final int maxSize;

    public Container(int maxSize) { this.maxSize = maxSize; }

    public synchronized void produce(Object item) throws InterruptedException {
        while (list.size() >= maxSize) wait();  // 滿了等待
        list.add(item);
        notifyAll();  // 喚醒消費者
    }

    public synchronized Object consume() throws InterruptedException {
        while (list.isEmpty()) wait();  // 空了等待
        Object item = list.remove(0);
        notifyAll();  // 喚醒生產者
        return item;
    }
}

生產者線程


class Producer implements Runnable {
    private final Container container;
    private int count = 0;

    Producer(Container c) { this.container = c; }

    @Override
    public void run() {
        try {
            while (true) {
                container.produce(new Object());
                System.out.println("生產第 " + (++count) + " 個");
                Thread.sleep(500);  // 模擬生產耗時
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

消費者線程


class Consumer implements Runnable {
    private final Container container;
    private int count = 0;

    Consumer(Container c) { this.container = c; }

    @Override
    public void run() {
        try {
            while (true) {
                container.consume();
                System.out.println("消費第 " + (++count) + " 個");
                Thread.sleep(1000);  // 模擬消費耗時
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

啟動測試


public class Main {
    public static void main(String[] args) {
        Container container = new Container(5);  // 容量 5
        new Thread(new Producer(container), "生產者").start();
        new Thread(new Consumer(container), "消費者").start();
    }
}

關鍵設計點解析

  1. while 而非 if:防止虛假喚醒,重新檢查條件
  2. notifyAll 而非 notify:多生產/消費者場景下,notify 可能喚醒同類角色導致繼續等待(信號丟失)
  3. 封裝同步邏輯:將 wait/notify 封裝在容器內部,業務代碼無感知,降低出錯概率
  4. 異常處理:捕獲 InterruptedException 並恢復中斷狀態,支持優雅關閉

現代替代方案:BlockingQueue


BlockingQueue<Object> queue = new ArrayBlockingQueue<>(5);
// 生產者:queue.put(item)  // 滿阻塞
// 消費者:queue.take()     // 空阻塞

JDK 並發包提供開箱即用的線程安全隊列,內部已正確實現等待/通知機制,生產環境強烈建議直接使用,避免手寫 wait/notify 的易錯細節。

總結

wait/notify/notifyAll 是基於對象監視器的底層協作原語,核心在於「條件檢查 + 釋放鎖等待 + 狀態改變後通知」。掌握其本質有助於理解高級併發組件原理,但實際開發請優先選用 BlockingQueue、Semaphore、CountDownLatch 等高級工具。

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