Blocking Queues

A blocking queue is a queue that blocks when you try to dequeue from it and the queue is empty, or if you try to enqueue items to it and the queue is already full. A thread trying to dequeue from an empty queue is blocked until some other thread inserts an item into the queue. A thread trying to enqueue an item in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more items or clearing the queue completely.
阻塞隊列是一個隊列:
情況1:希望出隊,但隊爲空 【直到其他線程將元素入隊,才結束阻塞】
情況2:希望入隊,但隊爲滿 【直到其他線程將元素出隊,才結束阻塞】

Here is a diagram showing two threads cooperating via a blocking queue:
在這裏插入圖片描述
A BlockingQueue with one thread putting into it, and another thread taking from it.
Java 5 comes with blocking queue implementations in the java.util.concurrent package. You can read about that class in my java.util.concurrent.BlockingQueue tutorial. Even if Java 5 comes with a blocking queue implementation, it can be useful to know the theory behind their implementation.
阻塞隊列實現是在java.util.concurrent.BlockingQueue ,這是接口

Blocking Queue Implementation

The implementation of a blocking queue looks similar to a Bounded Semaphore. Here is a simple implementation of a blocking queue:
blocking queue的實現類似於Bounded Semaphore

public class BlockingQueue {

  private List queue = new LinkedList();
  private int  limit = 10;

  public BlockingQueue(int limit){
    this.limit = limit;
  }

//入隊
  public synchronized void enqueue(Object item)
  throws InterruptedException  {
    while(this.queue.size() == this.limit) {
      wait(); //等待有元素出隊
    }
    //此時queue.size()<limit 也就是有空位,從而不用等待,直接入隊
    this.queue.add(item);
    if(this.queue.size() == 1) {
    //說明之前的隊是空的,現在有元素了,從而讓之前因沒元素無法出隊的線程執行
      notifyAll();
    }
  }


  public synchronized Object dequeue()
  throws InterruptedException{
    while(this.queue.size() == 0){
      wait(); //等待有元素入隊
    }
    if(this.queue.size() == this.limit){
     //因爲此時堆滿,若出隊,則queue.size()<limit,從而可以讓其他線程入隊notifyAll()
      notifyAll(); 
    }
    //若0<queue.size()<limit,則說明隊伍有元素,可以直接出隊。
    return this.queue.remove(0);
  }

}

在這裏插入圖片描述
Notice how notifyAll() is only called from enqueue() and dequeue() if the queue size is equal to the size bounds (0 or limit). If the queue size is not equal to either bound when enqueue() or dequeue() is called, there can be no threads waiting to either enqueue or dequeue items.
請注意,如果隊列大小等於大小界限(0或限制),則僅從enqueue()和dequeue()調用notifyAll()的方式。 如果在調用enqueue()或dequeue()時隊列大小不等於綁定的大小,則沒有線程等待入隊或出隊。

Java BlockingQueue Example

以下是基於典型的生產者-使用者場景的一個用例。注意,BlockingQueue 可以安全地與多個生產者和多個使用者一起使用。

class Producer implements Runnable {
   private final BlockingQueue queue;
   Producer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
 /*
 produce()方法是線程私有,所以它與線程是一一對應的
 quequ.put()是線程安全的,其放入隊列的對象是唯一的。
 */
       while(true) { queue.put(produce()); } 
     } catch (InterruptedException ex) { ... handle ...}
   }

   Object produce() { ... }
 }

 class Consumer implements Runnable {
   private final BlockingQueue queue;
   Consumer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
     /*
     queue.take()是線程安全的 也就是某個線程取出一個元素時,其他線程不會對這個元素進行取出更
    改等操作 Consumer是線程私有的,所以consume()並不用加synchronized
    */
       while(true) { consume(queue.take()); } 
     } catch (InterruptedException ex) { ... handle ...}
   }
   void consume(Object x) { ... }
 }

 class Setup {
   void main() {
     BlockingQueue q = new SomeQueueImplementation();
     Producer p = new Producer(q);
     Consumer c1 = new Consumer(q);
     Consumer c2 = new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
   }
 }
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章