1. 程式人生 > >Java 7中的TransferQueue 以及 SynchronousQueue

Java 7中的TransferQueue 以及 SynchronousQueue

doc article 在線 api 參數 java 7 發現 exec blocking

Java7中加入了JSR 166y規範對集合類和並發類庫的改進。其中的一項是增加了接口TransferQueue和其實現類LinkedTransferQueue

TransferQueue繼承了BlockingQueueBlockingQueue又繼承了Queue)並擴展了一些新方法。BlockingQueue(和Queue)是Java 5中加入的接口,它是指這樣的一個隊列:當生產者向隊列添加元素但隊列已滿時,生產者會被阻塞;當消費者從隊列移除元素但隊列為空時,消費者會被阻塞。

TransferQueue則更進一步,生產者會一直阻塞直到所添加到隊列的元素被某一個消費者所消費(不僅僅是添加到隊列裏就完事)。

新添加的transfer方法用來實現這種約束。顧名思義,阻塞就是發生在元素從一個線程transfer到另一個線程的過程中,它有效地實現了元素在線程之間的傳遞(以建立Java內存模型中的happens-before關系的方式)。

TransferQueue還包括了其他的一些方法:兩個tryTransfer方法,一個是非阻塞的,另一個帶有timeout參數設置超時時間的。還有兩個輔助方法hasWaitingConsumer()和getWaitingConsumerCount()。

當我第一次看到TransferQueue時,首先想到了已有的實現類SynchronousQueue。SynchronousQueue的隊列長度為0,最初我認為這好像沒多大用處,但後來我發現它是整個Java Collection Framework中最有用的隊列實現類之一,特別是對於兩個線程之間傳遞元素這種用例。

TransferQueue相比SynchronousQueue用處更廣、更好用,因為你可以決定是使用BlockingQueue的方法(譯者註:例如put方法)還是確保一次傳遞完成(譯者註:即transfer方法)。在隊列中已有元素的情況下,調用transfer方法,可以確保隊列中被傳遞元素之前的所有元素都能被處理。Doug Lea說從功能角度來講,LinkedTransferQueue實際上是ConcurrentLinkedQueue、SynchronousQueue(公平模式)和LinkedBlockingQueue的超集。而且LinkedTransferQueue更好用,因為它不僅僅綜合了這幾個類的功能,同時也提供了更高效的實現。

Joe Bowbeer提供了一篇William Scherer, Doug Lea, and Michael Scott的論文,在這篇論文中展示了LinkedTransferQueue的算法,性能測試的結果表明它優於Java 5的那些類(譯者註:ConcurrentLinkedQueue、SynchronousQueue和LinkedBlockingQueue)。LinkedTransferQueue的性能分別是SynchronousQueue的3倍(非公平模式)和14倍(公平模式)。因為像ThreadPoolExecutor這樣的類在任務傳遞時都是使用SynchronousQueue,所以使用LinkedTransferQueue來代替SynchronousQueue也會使得ThreadPoolExecutor得到相應的性能提升。考慮到executor在並發編程中的重要性,你就會理解添加這個實現類的重要性了。

Java 5中的SynchronousQueue使用兩個隊列(一個用於正在等待的生產者、另一個用於正在等待的消費者)和一個用來保護兩個隊列的鎖。而LinkedTransferQueue使用CAS操作(譯者註:參考wiki)實現一個非阻塞的方法,這是避免序列化處理任務的關鍵。這篇論文還羅列了很多的細節和數據,如果你感興趣,非常值得一讀。

SynchronousQueue

SynchronousQueue是這樣 一種阻塞隊列,其中每個 put 必須等待一個 take,反之亦然同步隊列沒有任何內部容量,甚至連一個隊列的容量都沒有。
不能在同步隊列上進行 peek,因為僅在試圖要取得元素時,該元素才存在;
除非另一個線程試圖移除某個元素,否則也不能(使用任何方法)添加元素;
也不能叠代隊列,因為其中沒有元素可用於叠代。隊列的頭是嘗試添加到隊列中的首個已排隊線程元素; 如果沒有已排隊線程,則不添加元素並且頭為 null。
對於其他 Collection 方法(例如 contains),SynchronousQueue 作為一個空集合。此隊列不允許 null 元素。
同步隊列類似於 CSP 和 Ada 中使用的 rendezvous 信道。
它非常適合於傳遞性設計,在這種設計中,在一個線程中運行的對象要將某些信息、
事件或任務傳遞給在另一個線程中運行的對象,它就必須與該對象同步。
對於正在等待的生產者和使用者線程而言,此類支持可選的公平排序策略。默認情況下不保證這種排序。
但是,使用公平設置為 true 所構造的隊列可保證線程以 FIFO 的順序進行訪問。 公平通常會降低吞吐量,但是可以減小可變性並避免得不到服務。

構造函數 技術分享

註意1:它一種阻塞隊列,其中每個 put 必須等待一個 take,反之亦然。
同步隊列沒有任何內部容量,甚至連一個隊列的容量都沒有。
註意2:它是線程安全的,是阻塞的。
註意3:不允許使用 null 元素。
註意4:公平排序策略是指調用put的線程之間,或take的線程之間。
公平排序策略可以查考ArrayBlockingQueue中的公平策略。
註意5:SynchronousQueue的以下方法很有趣:
* iterator() 永遠返回空,因為裏面沒東西。
* peek() 永遠返回null。
* put() 往queue放進去一個element以後就一直wait直到有其他thread進來把這個element取走。
* offer() 往queue裏放一個element後立即返回,如果碰巧這個element被另一個thread取走了,offer方法返回true,認為offer成功;否則返回false。
* offer(2000, TimeUnit.SECONDS) 往queue裏放一個element但是等待指定的時間後才返回,返回的邏輯和offer()方法一樣。
* take() 取出並且remove掉queue裏的element(認為是在queue裏的。。。),取不到東西他會一直等。
* poll() 取出並且remove掉queue裏的element(認為是在queue裏的。。。),只有到碰巧另外一個線程正在往queue裏offer數據或者put數據的時候,該方法才會取到東西。否則立即返回null。
* poll(2000, TimeUnit.SECONDS) 等待指定的時間然後取出並且remove掉queue裏的element,其實就是再等其他的thread來往裏塞。
* isEmpty()永遠是true。
* remainingCapacity() 永遠是0。
* remove()和removeAll() 永遠是false。

轉自:http://blog.csdn.net/hudashi/article/details/7076814

http://ifeve.com/java-transfer-queue/

http://www.cnblogs.com/wangzhongqiu/p/6441703.html

Java 7中的TransferQueue 以及 SynchronousQueue