使用 ReentrantLock 和 Condition 實現一個阻塞隊列


前言

從之前的阻塞隊列的源碼分析中,我們知道,JDK 中的阻塞隊列是使用 ReentrantLock 和 Condition 實現了,我們今天來個簡易版的。代碼如下:

代碼

public class BoundedBuffer {

  final ReentrantLock lock = new ReentrantLock();
  final ConditionObject notFull = (ConditionObject) lock.newCondition();
  final ConditionObject notEmpty = (ConditionObject) lock.newCondition();

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(Object x) throws InterruptedException {
    lock.lock();
    try {
      // 當數組滿了
      while (count == items.length) {
        // 釋放鎖,等待
        notFull.await();
      }
      // 放入數據
      items[putptr] = x;
      // 如果到最后一個位置了,下標從頭開始,防止下標越界
      if (++putptr == items.length) {
        // 從頭開始
        putptr = 0;
      }
      // 對 count ++ 加加
      ++count;
      // 通知 take 線程,可以取數據了,不必繼續阻塞
      notEmpty.signal();
    } finally {
      lock.unlock();
    }
  }

  public Object take() throws InterruptedException {
    lock.lock();
    try {
      // 如果數組沒有數據,則等待
      while (count == 0) {
        notEmpty.await();
      }
      // 取數據
      Object x = items[takeptr];
      // 如果到數組盡頭了,就從頭開始
      if (++takeptr == items.length) {
        // 從頭開始
        takeptr = 0;
      }
      // 將數量減1
      --count;
      // 通知阻塞的 put 線程可以裝填數據了
      notFull.signal();
      return x;
    } finally {
      lock.unlock();
    }
  }

其實,這並不是我寫的,而是 Condition 接口的 JavaDoc 文檔中寫的。並且文檔中說,請不要再次實現這個隊列,因為 JDK 內部已經是實現了。原話如下:

(The {@link java.util.concurrent.ArrayBlockingQueue} class provides this functionality, so there is no reason to implement this sample usage class.)

樓主只是覺得這個代碼寫的挺好的,所以分享一下,其中關鍵的還是 Condition 和重入鎖,重入鎖的核心源碼我們已經看過了,今天來看看 Condition 的源碼。所以我們今天使用了這個代碼作為一個入口。

可以看到,Condition 的重要方法就是 await 和 signal,類似 Object 類的 wait 和 notify 方法。

我們后面會詳細講講這兩個方法的實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM