2010-09-07 100 views
13

我有一個簡單的bean @Entity Message.java,它具有一些正常的屬性。該對象的生命週期是如下使用BlockingQueue時是否需要額外的同步?

消息的實例化發生在線程A,然後將其排隊到的BlockingQueue

從池中的另一個線程獲得該對象和做一些東西與它並改變Message的狀態,之後,對象再次進入blockingQueue。重複此步驟直到條件停止。每次對象讀取/寫入都可能來自不同的線程,但保證一次只有一個線程正在讀取/寫入。

鑑於這種情況,我是否需要同步getters/setters?也許使屬性變得不穩定?或者我可以離開而不同步?

感謝並希望我能澄清我在這裏所擁有的。

回答

25

不,您不需要同步對象屬性的訪問權限,甚至不需要對成員變量使用volatile

線程執行的所有操作在對象排隊之前發生的「發生之前」BlockingQueue上的對象。這意味着第一個線程所做的任何更改對第二個線程都是可見的。這是併發集合的常見行爲。請參閱最後一段the BlockingQueue class documentation.

只要第一個線程在排隊對象後不做任何修改,它就是安全的。

+2

用於提及BlockingQueue的線程可見性語義。 – Darron 2010-09-07 18:42:48

2

如果你確定一次只有一個線程可以訪問你的對象,那麼你不需要同步。

但是,可以保證使用synchronized關鍵字:您要訪問該對象,並確保沒有其他線程使用相同的實例,包你的代碼在一個同步塊中的每個時間:

Message myMessage = // ... 
synchronized (myMessage) { 
    // You're the only one to have access to this instance, do what you want 
} 

synchronized塊將獲取myMessage對象的隱式鎖定。因此,除非您離開此塊,否則其他同步塊將不能訪問同一實例。

+0

如果兩個線程實際上在對象上交錯,那麼同步單個getter和setter並不能真正證明任何事情。他們仍然會以不一致的狀態看到/做部分覆蓋。這個答案是解決問題的更好方法。 – Affe 2010-09-07 18:11:01

+0

@Vivien_Barousse所以,我並不需要同步任何東西,因爲不會同時訪問。這回答我的問題,謝謝! – 2010-09-07 18:14:35

3

你不需要自己做同步,因爲隊列已經爲你做了。

可見性也有保證。

0

這聽起來像你可以離開方法的同步。 synchronized會簡單地鎖定對象,只允許一個線程訪問它。您已經使用阻止隊列處理了該問題。

易失性將很好用,因爲這可以確保每個線程都有最新版本,而不是線程本地緩存值。

+0

在'BlockingQueue'中使用'volatile'是不必要的(並且效率低下)。 BlockingQueue合同的一部分是線程在排隊一個對象之前發生的任何動作「發生在該對象之前」被另一個線程出列。 – erickson 2010-09-07 18:15:29

+0

很高興知道。當另一個線程更改字段的值時,我知道volatile是需要的。這是有道理的,因爲當前線程請求值,阻塞線程會關心它。 – tylermac 2010-09-10 13:57:09

相關問題