2012-07-06 85 views
2

如果我有一個類,將其稱爲X,並且X包含一個集合(假設我沒有使用其中一個同步集合,只是一個普通集合)。同步關鍵字 - 它是如何工作的?

如果我要寫我自己的方法synchronized add() - 鎖定工作如何?鎖定是在X的實例上完成的,而不是在集合對象上完成的?

因此,同步我的add()方法不會阻止許多X實例調用add()並插入到集合中 - 因此我仍然可能遇到線程問題?

回答

4

同步方法鎖定對象。如果您的X.add已同步,則會阻止同時執行同一對象的其他同步方法。如果任何超出該X對象的人都可以訪問相同的集合,則集合將不受保護。

如果您希望您的藏品受到保護,請確保它不能以除X的同步方法以外的任何其他方式訪問。另外,這在你的問題中有點不清楚,但是請注意,一個同步的非靜態方法鎖定了對象。假設每個X實例都有自己的集合,它們不會互相干擾。

另一種選擇,順便說一句,是鎖定集合,而不是X對象:

void add(Object o) { 
    synchronized(myCollection) { 
     myCollection.add(o); 
    } 
} 

這將同步訪問鎖定的集合,而不是X對象。使用你認爲更容易和更有效的方法。

1

在您的示例中,​​將確保一次只有一個線程可以在該類的一個實例上調用該方法。其他方法可以訪問該集合,這是不安全的。請查閱concurrent collections以獲取有關線程安全收集實現的更多信息。

1

如果我要寫我自己的方法synchronized add() - 鎖定工作如何?鎖定是在X的實例上完成的,而不是在集合對象上完成的?

鎖定是在您同步的對象上完成的,而不是對象內的任何字段。爲了鎖定工作,所有的線程必須在同一個確切的對象上進行同步。通常最好鎖定private final對象。

private final Collection<...> myCollection = ... 
    ... 
    synchronize (myCollection) { 
     myCollection.add(...); 
    } 

雖然常見模式是鎖住你要保護的對象,它真的可以是任何常量對象。你也可以這樣做:

private final Object lockObject = new Object(); 
    ... 
    synchronize (lockObject) { 
     myCollection.add(...); 
    } 

所以我同步add()方法不會從調用add(),並插入到收藏 - 因此,我仍然可以有線程問題停止X的多個實例?

如果你的應用程序的其他部分正在訪問myCollection沒有是一個synchronized (myCollection)塊內,那麼,你將有線程問題。您需要同步全部的訪問權限才能正確保護收集並提供內存屏障。這意味着add(...),contains(...),迭代器等。

通常,如果您試圖保護集合或其他類,那麼將它包裝在執行同步的類中是有意義的。這隱藏了鎖定並保護了集合,使其不受代碼中的缺失​​塊的意外修改。

0

這是真的,你是跨共享許多x的實例一個集合?然後你需要在集合實例本身上進行同步。不要使方法本身​​,但將其所有代碼包含在synchronized(coll) { ... }塊中。

另一方面,如果每個X都有自己的集合,那麼synchronized add()就是您所需要的。這將保證沒有兩個線程同時在同一個實例上執行add