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

生產者-消費者模式:Java 多執行緒協作經典實現與阻塞隊列實戰

     編輯:Java 綜合教學

生產者-消費者模式:Java 多執行緒協作經典實現與阻塞隊列實戰

模式核心概念

生產者-消費者模式是經典的多執行緒設計模式,為多執行緒間協作提供優雅解決方案。模式包含兩類角色:生產者執行緒負責提交用戶請求/生產資料,消費者執行緒負責處理任務/消費資料。雙方透過共享記憶體緩衝區 (阻塞隊列) 進行資料通信,實現解耦合——生產者無需知曉消費者存在,反之亦然。緩衝區除實現資料共享外,還能緩解雙方處理速度差異帶來的效能瓶頸。

生產者-消費者模式架構圖

基於 BlockingQueue 的完整實現

Java java.util.concurrent 套件提供的 BlockingQueue 介面 (如 LinkedBlockingQueue) 內建執行緒安全的阻塞特性,是實現該模式的理想選擇。

共享資料模型 PCData

public final class PCData {
    private final int intData;
    public PCData(int intData) { this.intData = intData; }
    public PCData(String strData) { this.intData = Integer.valueOf(strData); }
    public synchronized int getIntData() { return intData; }
    @Override public String toString() { return "data:" + intData; }
}

生產者 Producer

public class Producer implements Runnable {
    private volatile boolean isRunning = true;
    private final BlockingQueue<PCData> queue;
    private static final AtomicInteger count = new AtomicInteger();
    private static final int SLEEP_TIME = 1000;

    public Producer(BlockingQueue<PCData> queue) { this.queue = queue; }

    @Override
    public void run() {
        System.out.println("生產者啟動 ID: " + Thread.currentThread().getId());
        Random r = new Random();
        try {
            while (isRunning) {
                Thread.sleep(r.nextInt(SLEEP_TIME));
                PCData data = new PCData(count.incrementAndGet());
                System.out.println(data + " 放入隊列");
                if (!queue.offer(data, 2, TimeUnit.SECONDS)) {
                    System.err.println("放入失敗: " + data);
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 重置中斷標誌
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void stop() { isRunning = false; }
}

消費者 Consumer

public class Consumer implements Runnable {
    private final BlockingQueue<PCData> queue;
    private static final int SLEEP_TIME = 1000;

    public Consumer(BlockingQueue<PCData> queue) { this.queue = queue; }

    @Override
    public void run() {
        System.out.println("消費者啟動 ID: " + Thread.currentThread().getId());
        Random r = new Random();
        try {
            while (true) {
                PCData data = queue.take(); // 阻塞直到取到資料
                int re = data.getIntData() * data.getIntData();
                System.out.println(data.getIntData() + "*" + data.getIntData() + "=" + re);
                Thread.sleep(r.nextInt(SLEEP_TIME));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客戶端啟動協作

public class Client {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<PCData> queue = new LinkedBlockingQueue<>(10); // 容量 10
        ExecutorService executor = Executors.newCachedThreadPool();

        // 啟動 3 生產者 + 3 消費者
        for (int i = 0; i < 3; i++) executor.execute(new Producer(queue));
        for (int i = 0; i < 3; i++) executor.execute(new Consumer(queue));

        Thread.sleep(10_000); // 運行 10 秒
        // 優雅關閉 (需 Producer 提供 stop 方法配合 volatile 標誌)
        // 此處為示範簡化,實際生產建議使用更完善的關閉機制
        executor.shutdown();
    }
}

模式優勢總結

  • 解耦合:生產者與消費者互不依賴,僅共享隊列介面。
  • 緩衝削峰:隊列吸收生產高峰,消費者按自身節奏處理,平滑流量衝擊。
  • 並發安全:BlockingQueue 內建鎖與條件變量,免去手動 wait/notify 的錯誤風險。
  • 靈活擴展:輕鬆調整生產者/消費者數量、隊列容量、處理邏輯,適應業務變化。

此模式廣泛應用於任務調度、日誌非同步寫入、訊息佇列消費、流量控制等高併發場景,是 Java 多執行緒開發必備利器。

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