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

Java 並發編程實戰:有界緩存四種實現演進(判斷前提、輪詢休眠、條件隊列、Lock/Condition)

     編輯:Java 綜合教學

有界緩存實現演進:從基類到生產級阻塞隊列

有界緩存是生產者-消費者模式的核心數據結構。本文展示四種實現版本的代碼演進,對比各自優缺點,最終落地生產可用的 BoundedBuffer。

版本一:基類 BaseBoundedBuffer

封裝循環數組、指針、計數器,提供線程安全的 doPut/doTake、isFull/isEmpty 基礎操作,所有方法 synchronized 修飾。

public class BaseBoundedBuffer<V> {
    private final V[] buf; private int tail, head, count;
    public BaseBoundedBuffer(int capacity) { this.buf = (V[]) new Object[capacity]; }
    protected synchronized final void doPut(V v) { buf[tail] = v; if (++tail == buf.length) tail = 0; ++count; }
    protected synchronized final V doTake() { V v = buf[head]; buf[head] = null; if (++head == buf.length) head = 0; --count; return v; }
    public synchronized final boolean isFull() { return count == buf.length; }
    public synchronized final boolean isEmpty() { return count == 0; }
}

版本二:GrumpyBoundedBuffer(判斷前提,失敗拋異常)

調用者需自行檢查狀態,隊列滿/空時拋出異常,不阻塞。適用於「寧可失敗不等待」的非關鍵路徑。

public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
    public synchronized void put(V v) throws Exception { if (isFull()) throw new Exception("隊列已滿"); doPut(v); }
    public synchronized V take() throws Exception { if (isEmpty()) throw new Exception("隊列為空"); return doTake(); }
}

版本三:SleepyBoundedBuffer(輪詢 + 休眠)

循環檢查條件,不滿足則 Thread.sleep() 釋放 CPU。缺點:延遲不可控(受睡眠粒度影響)、忙等待浪費 CPU、難以精確響應中斷。

public class SleepyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
    private static final long SLEEP_GRANULARITY = 2000;
    public void put(V v) throws InterruptedException {
        while (true) {
            synchronized (this) { if (!isFull()) { doPut(v); return; } }
            Thread.sleep(SLEEP_GRANULARITY);
        }
    }
    public V take() throws InterruptedException {
        while (true) {
            synchronized (this) { if (!isEmpty()) return doTake(); }
            Thread.sleep(SLEEP_GRANULARITY);
        }
    }
}

版本四:BoundedBuffer(條件隊列 wait/notifyAll —— 生產級標準)

利用對象監視器的 wait() 釋放鎖並掛起線程,notifyAll() 唤醒等待線程。完美解決「等待-通知」機制,無忙等待、響應及時、支持中斷。

public class BoundedBuffer<V> extends BaseBoundedBuffer<V> {
    public synchronized void put(V v) throws InterruptedException {
        while (isFull()) wait(); // 釋放鎖,進入 WAITING 狀態
        doPut(v);
        notifyAll(); // 唤醒所有等待線程(消費者)
    }
    public synchronized V take() throws InterruptedException {
        while (isEmpty()) wait();
        V v = doTake();
        notifyAll(); // 唤醒生產者
        return v;
    }
}

進階:Lock + Condition 實現(JUC 風格)

生產環境推薦使用 ReentrantLock 配合 Condition,支持多條件變量(notFull、notEmpty)、公平鎖、可中斷鎖獲取、超時等待等高級特性:

public class LockBoundedBuffer<V> {
    private final V[] buf; private int tail, head, count;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public void put(V v) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (count == buf.length) notFull.await();
            buf[tail] = v;
            if (++tail == buf.length) tail = 0;
            ++count;
            notEmpty.signal();
        } finally { lock.unlock(); }
    }
    public V take() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (count == 0) notEmpty.await();
            V v = buf[head];
            buf[head] = null;
            if (++head == buf.length) head = 0;
            --count;
            notFull.signal();
            return v;
        } finally { lock.unlock(); }
    }
}

總結對比

版本機制優點缺點適用場景
Grumpy檢查拋異常簡單、無阻塞調用者需重試、高併發下異常頻發非關鍵、可丟棄數據
Sleepy輪詢睡眠最終能成功延遲高、CPU 浪費、精度差教學演示、極低併發
BoundedBufferwait/notifyAll標準阻塞、無忙等待單一條件變量、notifyAll 唤醒過多一般生產環境
Lock+Condition顯式鎖+多條件精確唤醒、支持公平/中斷/超時代碼稍繁瑣高併發、高可靠生產環境

實際項目中,優先選用 java.util.concurrent 包下成熟組件:ArrayBlockingQueue、LinkedBlockingQueue,無需重複造輪子。

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