2010-07-26 20 views
6

我有3個主題:2個消費者,ConsumerAConsumerB,以及ProducerJava:LinkedBlockingQueue是否考慮到消費者的訂單?

我也有一個LinkedBlockingQueue queue

在t = 1:ConsumerA呼叫queue.take()

在t = 2:Consumer B調用queue.take()

在t = 3 :Producer調用queue.put(foo)

是否保證ConsumerA在ConsumerB之前接收到foo?換句話說,消費者調用take()的順序是通知每個消費者的順序?

如果沒有,是否有一個替代的數據結構會根據訂單給予更高的優先級?

回答

3

從源代碼看,它不能保證。根據調度程序的感覺,隨機喚醒一個線程有一個防護塊機制。

notEmpty.signal(); // propagate to a non-interrupted thread 

全碼:http://kickjava.com/src/java/util/concurrent/LinkedBlockingQueue.java.htm

編輯:剛剛又看了看ReenterantLock和條件,該線程在FIFO順序信號,顯然。所以,第一個等待插入的線程將首先被髮信號。但是,這些是實現細節!不要依賴他們。

的實現不需要 定義相同的保證或 語義所有三種形式的 等待,也不支持 中斷線程的實際掛起 它需要

3

在很多情況下,進入隊列的線程順序將以適當的順序排列。但是,LinkedBlocking隊列使用不公平的鎖定。這樣做可以讓線程互相駁接。雖然很少發生以下情況。

  • 線程A進入並輪詢。
  • 線程B進入嘗試輪詢 - 線程A持有鎖和公園螺紋B.
  • 線程A飾面和信號乙
  • 線程C進入和B在已啓動的完全
  • 線程B的嘗試之前獲得鎖輪詢 - 線程C持有鎖和公園線程B.

這是一種可能性。

1

所以通過Java 6源的深處挖掘(跳過水平線之間的部分,如果你不關心找到負責這個東西實際的代碼)


java.util.concurrent.LinkedBlockingQueue使用實現互斥 java.util.concurrent.locks.ReentrantLock的實例。

接着,使用java.util.concurrent.locks.ReentrantLock.newCondition()生成同步變量,其調用java.util.concurrent.locks.ReentrantLock$Sync.newCondition()

java.util.concurrent.locks.ReentrantLock$Sync.newCondition()返回java.util.concurrent.AbstractQueuedSynchronizer$ConditionObject一個實例,其實現由接口java.util.concurrent.locks.Condiion所述的正常同步變量調用await()signal()signalAll()和方法。


尋找在用於ConditionObject類的源代碼,它使兩個構件稱爲firstWaiterlastWaiter是在CLH鎖定隊列中第一個和最後節點(的java.util.concurrent.locks.AbstractQueuedSynchronizer$Node實例)。

在該類狀態的文檔:

線程可能會嘗試收購,如果它是第一個在隊列中。但首先並不能保證成功;它只會給予抗爭的權利。所以當前發佈的競爭者線程可能需要重新等待。

所以我相信這裏的答案是,在LinkedBlockingQueue企圖take()方法優待那些所謂take()較早線程。它會給第一個線程呼叫take()第一次獲取隊列項目的機會,但是由於超時,中斷等原因不能保證成爲第一個從項目中獲取項目的線程隊列。

請記住,這是完全特定於此特定實施。一般來說,假設在take()的調用將喚醒一個隨機等待線程,當一個隊列項目變得可用時,不一定是第一個調用take()的線程。

相關問題