2013-10-21 52 views
0

我想以線程安全的方式存儲對象列表,同時保持優先級。本來我開始使用BlockingQueue,因爲它是線程安全的,並且有能力維護自定義優先級。我是否需要將呼叫同步到BlockingQueue(java)?

我在想我是否需要同步我的方法?我的代碼如下所示:

void addToQueue(SomeObject obj) { 
    ... put it on my priority queue 
    ... do some logging 
} 

我已經注意到的是記錄正在發生失靈,從多個線程訪問addToQueue時。所以我用這樣的方法包裝了我的方法:

void addToQueue(SomeObject obj) { 
    syncronized(myMutex) { 
     ... put it on my priority queue 
     ... do some logging 
    } 
} 

這似乎是爲了保持記錄的順序。所以現在我得出結論,如果我要走這條路線,那麼也許我的代碼會更有效率,因爲不使用BlockingQueue,而是使用Set或List並自己管理優先級。

也許我對BlockingQueue有一些誤解。

+2

在'BlockingQueue'同步的唯一的事情就是在各個方法的代碼的一部分。日誌記錄不是「BlockingQueue」的一部分,因此不會受其執行限制。 –

+0

這是一個對象集合嗎?批量集合操作addAll,containsAll,retainAll和removeAll不一定以原子方式執行,除非在實現中另行指定。因此,例如,在添加c中的一些元素後,addAll(c)可能會失敗(拋出異常)。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html – JNL

+0

本質上,BlockingQueue具有阻塞操作,所以要小心在同步部分內進行阻塞調用代碼,否則你可能會陷入僵局。 – jekennedy

回答

1

另外支持在檢索元素時等待隊列變爲非空操作的隊列,並且在存儲元素時等待隊列中的空間變得可用。

這是用於BlockingQueue的javadoc。如果你需要這種阻塞行爲,你可以使用它,否則你不需要。

BlockingQueue確實不是保持任何優先級,這是嚴格先進先出。也許您正在使用PriorityBlockingQueue

來到你的僞代碼:

void addToQueue(SomeObject obj) { 
    ... put it on my priority queue 
    ... do some logging 
} 

隊列是線程安全的,但是,這隻意味着多個線程可以同時調用put it on my priority queue數據沒有遭到損壞。它不保證以下任何一項:

  • 如果有多個線程阻塞哪一個會成功的第一
  • 如果thread X完成putthread Y然後thread X還將thread Y前完成logging

如果你需要所有addToQueue發生沒有從其他線程交錯,那麼你需要同步。請注意,您可以使用隊列對象本身:

void addToQueue(SomeObject obj) { 
    synchronized (queue) { 
     ... put it on my priority queue 
     ... do some logging 
    } 
} 
0

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

與其他併發集合之前,在一個線程動作將對象放入到該元素的從BlockingQueue的另一線程中訪問或移除之後的的BlockingQueue發生-之前的動作。

如果您想使用安全得到有序的記錄,你必須登錄之前把物品放入隊列,並從隊列中取出一個項目後

我不會使用​​來獲得有序的日誌記錄。多線程意味着並行執行,這意味着某些操作沒有排序。日誌記錄可以有一個時間戳,並以錯誤的順序看到它們,即在控制檯中,對我來說看起來像是一個小毛病,不值得犧牲並行執行的優點。