java BlockingQueue之ArrayBlockingQueue

JAVA API中這樣解釋BlockingQueue:

支持兩個附加操作的 Queue,這兩個操作是:獲取元素時等待隊列變爲非空,以及存儲元素時等待空間變得可用。

BlockingQueue 方法以四種形式出現,對於不能立即滿足但可能在將來某一時刻可以滿足的操作,這四種形式的處理方式不同:第一種是拋出一個異常,第二種是返回一個特殊值(nullfalse,具體取決於操作),第三種是在操作可以成功前,無限期地阻塞當前線程,第四種是在放棄前只在給定的最大時間限制內阻塞。下表中總結了這些方法:

  拋出異常 特殊值 阻塞 超時
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
檢查 element() peek() 不可用 不可用

BlockingQueue 不接受 null 元素。試圖 addput offer 一個 null 元素時,某些實現會拋出 NullPointerExceptionnull 被用作指示poll 操作失敗的警戒值。

先看一個簡單的實現例子:

public class BoundedBuffer {

 //可中斷同步鎖
 final Lock lock = new ReentrantLock();
 final Condition notFull = lock.newCondition();
 final Condition notEmpty = 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;
   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;
   --count;
   notFull.signal();
   return x;
  } finally {
   lock.unlock();
  }
 }

}

上面的例子展示了一個定長的隊列,提供了存放和提取數據的方法,且使用ReentrantLock來實現同步。
再來看看SUN的實現:

private static final long serialVersionUID = -817911632652898426L;
  private final E[] items;
  private int takeIndex;
  private int putIndex;
  private int count;
  private final ReentrantLock lock;
  private final Condition notEmpty;
  private final Condition notFull;

public ArrayBlockingQueue(int paramInt)
  {
    this(paramInt, false);
  }
  //初始構造函數
  public ArrayBlockingQueue(int paramInt, boolean paramBoolean)
  {
    if (paramInt <= 0)
      throw new IllegalArgumentException();
    this.items = ((Object[])new Object[paramInt]);
    //初始化鎖對象
    this.lock = new ReentrantLock(paramBoolean);
    this.notEmpty = this.lock.newCondition();
    this.notFull = this.lock.newCondition();
  }
  //put的實現
  public void put(E paramE)
    throws InterruptedException
  {
    if (paramE == null)
      throw new NullPointerException();
    Object[] arrayOfObject = this.items;
    ReentrantLock localReentrantLock = this.lock;
    //如果當前線程未被中斷則獲取鎖
    localReentrantLock.lockInterruptibly();
    try
    {
      try
      {
        while (this.count == arrayOfObject.length)
          //數組已滿 等待直到被喚醒或中斷
          this.notFull.await();
      }
      catch (InterruptedException localInterruptedException)
      {
        //被中斷則喚醒
        this.notFull.signal();
        throw localInterruptedException;
      }
      insert(paramE);
    }
    finally
    {
      localReentrantLock.unlock();
    }
  }
  private void insert(E paramE)
  {
    this.items[this.putIndex] = paramE;
    this.putIndex = inc(this.putIndex);
    this.count += 1;
    //喚醒持有notEmpty等待的線程
    this.notEmpty.signal();
  }
  
  public E take()
    throws InterruptedException
  {
    ReentrantLock localReentrantLock = this.lock;
    //獲取鎖
    localReentrantLock.lockInterruptibly();
    try
    {
      try
      {
        while (this.count == 0)
        //空則等待
          this.notEmpty.await();
      }
      catch (InterruptedException localInterruptedException)
      {
      //喚醒
        this.notEmpty.signal();
        throw localInterruptedException;
      }
      Object localObject1 = extract();
      Object localObject2 = localObject1;
      return localObject2;
    }
    finally
    {
      localReentrantLock.unlock();
    }
  }
  
  private E extract()
  {
    Object[] arrayOfObject = this.items;
    Object localObject = arrayOfObject[this.takeIndex];
    arrayOfObject[this.takeIndex] = null;
    this.takeIndex = inc(this.takeIndex);
    this.count -= 1;
    //喚醒等待的線程
    this.notFull.signal();
    return localObject;
  }


 

 

public ArrayBlockingQueue(int paramInt)
  {
    this(paramInt, false);
  }
  //初始構造函數
  public ArrayBlockingQueue(int paramInt, boolean paramBoolean)
  {
    if (paramInt <= 0)
      throw new IllegalArgumentException();
    this.items = ((Object[])new Object[paramInt]);
    //初始化鎖對象
    this.lock = new ReentrantLock(paramBoolean);
    this.notEmpty = this.lock.newCondition();
    this.notFull = this.lock.newCondition();
  }
  //put的實現
  public void put(E paramE)
    throws InterruptedException
  {
    if (paramE == null)
      throw new NullPointerException();
    Object[] arrayOfObject = this.items;
    ReentrantLock localReentrantLock = this.lock;
    //如果當前線程未被中斷則獲取鎖
    localReentrantLock.lockInterruptibly();
    try
    {
      try
      {
        while (this.count == arrayOfObject.length)
          //數組已滿 等待直到被喚醒或中斷
          this.notFull.await();
      }
      catch (InterruptedException localInterruptedException)
      {
        //被中斷則喚醒
        this.notFull.signal();
        throw localInterruptedException;
      }
      insert(paramE);
    }
    finally
    {
      localReentrantLock.unlock();
    }
  }
  private void insert(E paramE)
  {
    this.items[this.putIndex] = paramE;
    this.putIndex = inc(this.putIndex);
    this.count += 1;
    //喚醒持有notEmpty等待的線程
    this.notEmpty.signal();
  }
  
  public E take()
    throws InterruptedException
  {
    ReentrantLock localReentrantLock = this.lock;
    //獲取鎖
    localReentrantLock.lockInterruptibly();
    try
    {
      try
      {
        while (this.count == 0)
        //空則等待
          this.notEmpty.await();
      }
      catch (InterruptedException localInterruptedException)
      {
      //喚醒
        this.notEmpty.signal();
        throw localInterruptedException;
      }
      Object localObject1 = extract();
      Object localObject2 = localObject1;
      return localObject2;
    }
    finally
    {
      localReentrantLock.unlock();
    }
  }
  
  private E extract()
  {
    Object[] arrayOfObject = this.items;
    Object localObject = arrayOfObject[this.takeIndex];
    arrayOfObject[this.takeIndex] = null;
    this.takeIndex = inc(this.takeIndex);
    this.count -= 1;
    //喚醒等待的線程
    this.notFull.signal();
    return localObject;
  }

以上只貼出了部分源碼,ArrayBlockingQueue還提供了其他三種處理方式,有興趣的可以自己去研讀。

 

下面是一個小例子:

public class Setup {
 class Producer implements Runnable {
  volatile int i=0;
     private final BlockingQueue<String> queue;
     public Producer(BlockingQueue<String> q) { queue = q; }
     public void run() {
      try {
       while(true&&i<1000) { 
        queue.put(produce());
       }
      } catch (InterruptedException ex) 
      {
       ex.printStackTrace();
      }
     }
    String produce(){
     i++;
     return "put"+i;
    }
 }

 class Consumer implements Runnable {
  private final BlockingQueue<String> queue;
     Consumer(BlockingQueue<String> q) { queue = q; }
     public void run() {
      try {
       while(true) { 
        synchronized (lock) {
         System.out.println(queue.take()); 
     }
        
       }
      } catch (InterruptedException ex) 
      { 
       ex.printStackTrace();
      }
     }
  }

 Object lock = new Object();
   
 public static void main(String args[]){
  Setup s = new Setup();
  BlockingQueue<String> q = new ArrayBlockingQueue<String>(1);
     Producer p = s.new Producer(q);
     Consumer c1 = s.new Consumer(q);
     Consumer c2 = s.new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
 }
}


 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章