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

Java 並發協作:生產者-消費者-倉儲模型實戰

     編輯:Java 相關知識

模型核心角色與規則

準確說應為「生產者-消費者-倉儲」三方協作。核心邏輯:

  1. 生產者僅在倉儲未滿時生產,滿則等待
  2. 消費者僅在倉儲有貨時消費,空則等待
  3. 消費者發現空倉時通知生產者生產
  4. 生產者生產出貨時通知等待的消費者

實現依賴 Object 的 wait()、notifyAll() 機制。

完整代碼實現

/** 
 * Java線程:並發協作-生產者消費者模型
 * @author leizhimin
 */
public class Test {
    public static void main(String[] args) {
        Godown godown = new Godown(30); // 初始庫存30
        // 3消費者,7生產者
        new Consumer(50, godown).start();
        new Consumer(20, godown).start();
        new Consumer(30, godown).start();
        new Producer(10, godown).start();
        new Producer(10, godown).start();
        new Producer(10, godown).start();
        new Producer(10, godown).start();
        new Producer(10, godown).start();
        new Producer(10, godown).start();
        new Producer(80, godown).start();
    }
}

/** 倉庫:共享資源,內建同步協作邏輯 */
class Godown {
    public static final int max_size = 100; // 最大容量
    public int curnum; // 當前庫存
    
    Godown() {}
    Godown(int curnum) { this.curnum = curnum; }
    
    /** 生產指定數量 */
    public synchronized void produce(int neednum) {
        while (neednum + curnum > max_size) { // 條件不滿足,等待
            System.out.println("要生產的產品數量" + neednum + "超過剩余庫存量" + (max_size - curnum) + ",暫時不能執行生產任務!");
            try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
        }
        curnum += neednum; // 執行生產
        System.out.println("已經生產了" + neednum + "個產品,現倉儲量為" + curnum);
        notifyAll(); // 喚醒所有等待者
    }
    
    /** 消費指定數量 */
    public synchronized void consume(int neednum) {
        while (curnum < neednum) { // 條件不滿足,等待
            try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
        }
        curnum -= neednum; // 執行消費
        System.out.println("已經消費了" + neednum + "個產品,現倉儲量為" + curnum);
        notifyAll(); // 喚醒所有等待者
    }
}

/** 生產者線程 */
class Producer extends Thread {
    private int neednum; private Godown godown;
    Producer(int neednum, Godown godown) { this.neednum = neednum; this.godown = godown; }
    public void run() { godown.produce(neednum); }
}

/** 消費者線程 */
class Consumer extends Thread {
    private int neednum; private Godown godown;
    Consumer(int neednum, Godown godown) { this.neednum = neednum; this.godown = godown; }
    public void run() { godown.consume(neednum); }
}

運行結果分析

已經生產了10個產品,現倉儲量為40
已經生產了10個產品,現倉儲量為50
已經消費了50個產品,現倉儲量為0
已經生產了80個產品,現倉儲量為80
已經消費了30個產品,現倉儲量為50
已經生產了10個產品,現倉儲量為60
已經消費了20個產品,現倉儲量為40
已經生產了10個產品,現倉儲量為50
已經生產了10個產品,現倉儲量為60
已經生產了10個產品,現倉儲量為70
Process finished with exit code 0

流程解讀:

  • 初始30,兩生產者各+10 → 50
  • 消費者-50 → 0(倉空)
  • 生產者+80 → 80
  • 消費者-30 → 50
  • 後續生產者依次+10,消費者-20,庫存波動但始終在 0-100 範圍

關鍵機制說明

  • while 而非 if:防止虛假喚醒,重新檢查條件
  • wait() 釋放鎖:讓其他線程能進入同步方法檢查條件
  • notifyAll() 僅通知:不釋放鎖,喚醒線程需重新競爭鎖
  • 同步方法隱含鎖:synchronized 方法鎖住 Godown 實例

模型局限與改進方向

  • 若無生產者、消費者需求超庫存,程序永久等待
  • 改進:引入超時機制、最大等待時間、或基於消費驅動生產的動態調整
  • 生產環境建議使用 BlockingQueue 等高級併發組件替代手動 wait/notify

出處:https://lavasoft.blog.51cto.com/62575/221932

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