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

Java 並發編程:線程間通信 wait/notify 生產者消費者模式

     編輯:Java 綜合教學

Java 並發編程:線程間通信 wait/notify 生產者消費者模式

通過共享資源對象實現線程協作,演示 synchronized + wait()/notify() 經典生產者-消費者模式,解決線程安全與高效協作問題。

核心組件設計

  • Resource:共享數據載體 (name、sex)
  • Input (生產者):循環寫入中文/拼音數據
  • Output (消費者):循環讀取並打印
  • 鎖對象:唯一的 Resource 實例

完整代碼實現

class Resource {
    String name;
    String sex;
}

class Input implements Runnable {
    private final Resource resource;
    public Input(Resource resource) { this.resource = resource; }
    
    @Override
    public void run() {
        boolean toggle = true;
        while (true) {
            synchronized (resource) { // 獲取鎖
                if (toggle) {
                    resource.name = "陶士涵";
                    resource.sex = "男";
                } else {
                    resource.name = "taoshihan";
                    resource.sex = "nan";
                }
                toggle = !toggle;
                resource.notify(); // 喚醒消費者
                try {
                    resource.wait(); // 釋放鎖並等待
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
    }
}

class Output implements Runnable {
    private final Resource resource;
    public Output(Resource resource) { this.resource = resource; }
    
    @Override
    public void run() {
        while (true) {
            synchronized (resource) {
                System.out.println(resource.name + "=====" + resource.sex);
                resource.notify(); // 喚醒生產者
                try {
                    resource.wait(); // 釋放鎖並等待
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
    }
}

public class WaitNotifyDemo {
    public static void main(String[] args) {
        Resource resource = new Resource(); // 唯一共享對象
        new Thread(new Input(resource), "生產者").start();
        new Thread(new Output(resource), "消費者").start();
    }
}

運行效果

陶士涵=====男
taoshihan=====nan
陶士涵=====男
taoshihan=====nan
... 交替輸出,無數據錯亂

關鍵點深度解析

1. 同步前提:同一把鎖

  • 生產者、消費者 synchronized(resource) 使用同一實例
  • 若鎖不一致,wait/notify 會拋 IllegalMonitorStateException

2. wait/notify 語義

3. 經典協作流程

  1. 生產者獲取鎖 → 生產數據 → notify() 喚醒消費者 → wait() 釋放鎖等待
  2. 消費者獲取鎖 → 消費數據 → notify() 喚醒生產者 → wait() 釋放鎖等待
  3. 循環往複,實現嚴格交替

4. 死鎖風險

  • 嵌套同步塊且鎖順序不一致
  • 忘記 notify() 導致永久等待
  • 使用 notifyAll() 替代 notify() 可減少信號丟失風險 (多消費者場景)

現代替代方案 (JUC)

生產環境推薦使用 java.util.concurrent 組件,更安全、功能更豐富:

方法釋放鎖線程狀態喚醒方式
wait()是WAITINGnotify()/notifyAll()
sleep()否TIMED_WAITING時間到期自動

BlockingQueue 版生產消費者 (推薦)

BlockingQueue queue = new ArrayBlockingQueue<>(10);

new Thread(() -> {
    while (true) {
        queue.put("data-" + System.currentTimeMillis()); // 滿則阻塞
    }
}, "Producer").start();

new Thread(() -> {
    while (true) {
        System.out.println("Consumed: " + queue.take()); // 空則阻塞
    }
}, "Consumer").start();
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景推薦類優勢
有界隊列生產消費ArrayBlockingQueue內置阻塞、無需手動 wait/notify
延遲任務DelayQueue按時間排序
線程協作CountDownLatch/CyclicBarrier/Phaser語義清晰、可復用
鎖替代ReentrantLock + Condition多條件隊列、可中斷、公平鎖