3

我在java中有一個讀取UDP數據包並將它們放入一個對象中的類(基本上是無限循環)。然後這個對象在多個單獨的線程中被訪問,但很明顯,因爲它被同時填充,所有這些getters/setter都在同步方法中。問題是,現在這些干將有這樣的代碼:Java同步對象?

public synchronized SomeObject exampleGetter() { 
    if(this.isReceiving) 
     return oldCachedObject; 
    else 
     return currentObject; 
} 

顯然,這並不完全做的事情最好的辦法,所以我應該怎麼去寫方法(大量不同者),其完全鎖定對象一次一個線程並阻止其他線程(包括首先創建對象的線程)?我查看了同步塊,但我對於「鎖定對象」具有什麼效果感到困惑,是否在該給定時間有權訪問塊的對象?任何意見,將不勝感激。謝謝!

+3

在[Java併發實踐(http://jcip.net/)看看。 – ObscureRobot 2011-12-21 20:42:12

+1

google'java /'consumer' – 2011-12-21 20:49:22

回答

5

​​關鍵字在整個對象實例上同步,而不僅僅是setter。我寧願選擇細粒度的鎖定策略或更好的方法......使用線程安全的數據結構來存儲和獲取接收到的數據。我個人喜歡BlockingQueue<T>,其中T是您在網絡上收到的數據類型。

因此,假設您收到Object s傳輸插座:

public class ReceivedDataHolder{ 
    BlockingQueue<Object> dataBuffer = new LinkedBlockingQueue<Object>(); 
    //... 
    public void dataReceived(Object data){ 
     dataBuffer.offer(data); 
    } 

    public Object getReceivedData(){ 
     return dataBuffer.take(); 
    } 
} 

而在你的插槽,你可以做到這一點,只要你收到數據:

receivedDataHolder.dataReceived(object); 

想要獲取數據的任何線程應做:

receivedDataHolder.getReceivedData(); 

這後一個方法調用將阻止調用線程unt金正日沒有在隊列中可用的元素(檢查this出更多細節)

我希望這有助於

+2

'BlockingQueue'是一個接口,所以'new BlockingQueue ();'不會編譯。您必須使用實現接口的具體類,例如'ArrayBlockingQueue '或'LinkedBlockingQueue ',這是生產者/消費者最常用的具體阻塞隊列。 – 2011-12-22 04:12:43

+0

@BrunoReis的確,我的一個小錯誤。它現在是固定的 – GETah 2011-12-22 09:02:20

0

Java中的所有對象已經一些所謂的內在鎖,如果任何線程想要做的任何對象上的任何操作那麼它需要獲取該對象的固有鎖定。它將保證在任何給定時間只有1個線程會處理你的代碼塊。

線程可以獲得對任何對象的鎖定,如果該對象未被任何其他線程鎖定,並且該鎖定被鎖定,則該線程將等待另一個線程釋放對該對象的鎖定。

如果你使用synchronized塊,你的代碼會有點像這個

public void SomeObject exampleGetter() { 

synchronized(this) 
{ 


if(this.isReceiving) 
     return oldCachedObject; 
    else 
     return currentObject; 


} 

在這種情況下,當你的線程進入synchronized塊時,如果任何其他線程是有這個對象上的鎖,那麼它會等待直到該線程釋放鎖定。如果該對象是空閒的,那麼你的線程將獲得這個對象上的鎖並執行該操作,然後釋放該對象上的鎖。

對synchronized塊,方法和內部鎖的詳細信息,請參閱 http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

我希望它幫你:)

+3

完全無意義:*「如果任何線程想要對任何對象執行任何操作,那麼它需要獲取該對象的內部鎖定」*。任何線程都可以對任何已知對象執行任何操作,而無需獲取任何類型的鎖。 – 2011-12-22 04:14:05