佇列(Queue)是個先前先出(First In First
Out, FIFO)的資料結構。在JDK 5.0中新增了Blocking Queue,在多執行緒的情況下,如果Blocking
Queue的內容為空,而有個執行緒試圖從Queue中取出元素,則該執行緒會被Block,直到Queue有元素時才解除Block,反過來說,如果
Blocking
Queue滿了,而有個執行緒試圖再把資料填入Queue中,則該執行緒會被Block,直到Queue中有元素被取走後解除Block。
BlockingQueue的幾個主要操作為下:
方法 |
說明 |
add |
加入元素,如果佇列是滿的,則丟出IllegalStateException |
remove |
傳回並從佇列移除元素,如果佇列是空的,則丟出NoSuchElementException |
element |
傳回元素,如果佇列是空的,則丟出NoSuchElementException |
offer |
加入元素並傳回true,如果佇列是滿的,則傳回false |
poll |
傳回並從佇列移除元素,如果佇列是空的,則傳回null |
peek |
傳回元素,如果佇列是空的,則傳回null |
put |
加入元素,如果佇列是滿,就block |
take |
傳回並移除元素,如果佇列是空的,就block |
在java.util.concurrent下提供幾種不同的Blocking Queue,ArrayBlockingQueue要指定容量大小來建構,LinkedBlockingQueue預設沒有容量上限,但也可以指定容量上限,PriorityBlockingQueue是根據優先權(Priority)來移除元素。
在這邊以 wait()、notify() 中的生產者、消費者程式為例,使用BlockQueue來加以改寫,好處是我們不用親自處理wait、notify的細節,首先生產者改寫如下:
package onlyfun.caterpillar;
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable { private BlockingQueue<Integer> queue; public Producer(BlockingQueue<Integer> queue) { this.queue = queue; }
public void run() { for(int product = 1; product <= 10; product++) { try { // wait for a random time Thread.sleep((int) Math.random() * 3000); queue.put(product); } catch(InterruptedException e) { e.printStackTrace(); } } } }
消費者類別改寫如下:
package onlyfun.caterpillar;
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable { private BlockingQueue<Integer> queue; public Consumer(BlockingQueue<Integer> queue) { this.queue = queue; } public void run() { for(int i = 1; i <= 10; i++) { try { // wait for a random time Thread.sleep((int) (Math.random() * 3000)); queue.take(); } catch(InterruptedException e) { e.printStackTrace(); } } } }
可以使用下面這個程式來簡單的測試一下:
package onlyfun.caterpillar;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo { public static void main(String[] args) { BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(1); Thread producerThread = new Thread(new Producer(queue)); Thread consumerThread = new Thread(new Consumer(queue)); producerThread.start(); consumerThread.start(); } }
|