1. java.util.concurrent - Java 並發工具包 Java 5 添加了一個新的包到 Java 平台,java.util.concurrent 包。這個包包含有一系列能夠讓 Java 的並發編程變得更加簡單輕鬆的類。在這個包被添加以前,你需要自己去動手實現自己的相關工具類。
本文我將帶你一一認識 java.util.concurrent 包裡的這些類,然後你可以嘗試著如何在項目中使用它們。本文中我將使用 Java 6 版本,我不確定這和 Java 5 版本裡的是否有一些差異。
我不會去解釋關於 Java 並發的核心問題 - 其背後的原理,也就是說,如果你對那些東西感興趣,參考《 Java 並髮指南 》。
半成品
本文很大程度上還是個 "半成品",所以當你發現一些被漏掉的類或介面時,請耐心等待。在我閒置時候會把它們加進來的。
2. 阻塞隊列 BlockingQueue java.util.concurrent 包裡的 BlockingQueue 介面表示一個線程安放入和提取執行個體的隊列。本小節我將給你示範如何使用這個 BlockingQueue。
本節不會討論如何在 Java 中實現一個你自己的 BlockingQueue。如果你對那個感興趣,參考《 Java 並髮指南 》
BlockingQueue 用法 BlockingQueue 通常用於一個線程生產對象,而另外一個線程消費這些對象的情境。下圖是對這個原理的闡述:
一個線程往裡邊放,另外一個線程從裡邊取的一個 BlockingQueue。
一個線程將會持續生產新對象並將其插入到隊列之中,直到隊列達到它所能容納的臨界點。也就是說,它是有限的。如果該阻塞隊列到達了其臨界點,負責生產的線程將會在往裡邊插入新對象時發生阻塞。它會一直處於阻塞之中,直到負責消費的線程從隊列中拿走一個對象。
負責消費的線程將會一直從該阻塞隊列中拿出對象。如果消費線程嘗試去從一個空的隊列中提取對象的話,這個消費線程將會處於阻塞之中,直到一個生產線程把一個對象丟進隊列。
BlockingQueue 的方法 BlockingQueue 具有 4 組不同的方法用於插入、移除以及對隊列中的元素進行檢查。如果請求的操作不能得到立即執行的話,每個方法的表現也不同。這些方法如下:
| |
拋異常 |
特定值 |
阻塞 |
逾時 |
| 插入 |
add(o) |
offer(o) |
put(o) |
offer(o, timeout, timeunit) |
| 移除 |
remove(o) |
poll(o) |
take(o) |
poll(timeout, timeunit) |
| 檢查 |
element(o) |
peek(o) |
|
|
四組不同的行為方式解釋:
拋異常:如果試圖的操作無法立即執行,拋一個異常。
特定值:如果試圖的操作無法立即執行,返回一個特定的值(常常是 true / false)。
阻塞:如果試圖的操作無法立即執行,該方法調用將會發生阻塞,直到能夠執行。
逾時:如果試圖的操作無法立即執行,該方法調用將會發生阻塞,直到能夠執行,但等待時間不會超過給定值。返回一個特定值以告知該操作是否成功(典型的是 true / false)。 無法向一個 BlockingQueue 中插入 null。如果你試圖插入 null,BlockingQueue 將會拋出一個 NullPointerException。
可以訪問到 BlockingQueue 中的所有元素,而不僅僅是開始和結束的元素。比如說,你將一個對象放入隊列之中以等待處理,但你的應用想要將其取消掉。那麼你可以調用諸如 remove(o) 方法來將隊列之中的特定對象進行移除。但是這麼幹效率並不高(譯者註:基於隊列的資料結構,擷取除開始或結束位置的其他對象的效率不會太高),因此你盡量不要用這一類的方法,除非你確實不得不那麼做。
BlockingQueue 的實現 BlockingQueue 是個介面,你需要使用它的實現之一來使用 BlockingQueue。java.util.concurrent 具有以下 BlockingQueue 介面的實現(Java 6):
ArrayBlockingQueue DelayQueue LinkedBlockingQueue PriorityBlockingQueue SynchronousQueue
Java 中使用 BlockingQueue 的例子 這裡是一個 Java 中使用 BlockingQueue 的樣本。本樣本使用的是 BlockingQueue 介面的 ArrayBlockingQueue 實現。
首先,BlockingQueueExample 類分別在兩個獨立的線程中啟動了一個 Producer 和 一個 Consumer。Producer 向一個共用的 BlockingQueue 中注入字串,而 Consumer 則會從中把它們拿出來。
[java] view plain copy print ? public class BlockingQueueExample { public static void main(String[] args) throws Exception { BlockingQueue queue = new ArrayBlockingQueue(1024); Producer producer = new Producer(queue); Consumer consumer = new Consumer(queue); new Thread(producer).start(); new Thread(consumer).start(); Thread.sleep(4000); } }
以下是 Producer 類。注意它在每次 put() 調用時是如何休眠一秒鐘的。這將導致 Consumer 在等待隊列中對象的時候發生阻塞。
[java] view plain copy print ? public class Producer implements Runnable{ protected BlockingQueue queue = null; public Producer(BlockingQueue queue) { this.queue = queue; } public void run() { try { queue.put("1"); Thread.sleep(1000);