我跑進一些(生產!)的代碼看起來像下面的代碼片段:分配基於該對象的synchronized塊中的對象(JAVA)
synchronized(some_object) {
some_object = new some_object()
}
我希望這是受到各種可怕的競態條件,並且第二個線程可能會輸入這個塊來創建新的對象。我的Java版本不夠好,無法明確說明上面的預期行爲,所以很好奇你們在重構這個之前不得不說的話。
我跑進一些(生產!)的代碼看起來像下面的代碼片段:分配基於該對象的synchronized塊中的對象(JAVA)
synchronized(some_object) {
some_object = new some_object()
}
我希望這是受到各種可怕的競態條件,並且第二個線程可能會輸入這個塊來創建新的對象。我的Java版本不夠好,無法明確說明上面的預期行爲,所以很好奇你們在重構這個之前不得不說的話。
弗朗西斯說,這可能不是一個問題。您的片段等同於:
SomeObject saved = some_object;
synchronized(saved) {
some_object = new SomeObject()
}
這實際上可以確定取決於發生了什麼。您需要了解更大的上下文。同步將位於塊開始處some_object
指向的對象上。您的描述中沒有足夠的信息來查看這是一個錯誤。
同步本身將工作得很好。
同步在進入同步塊時被引用的對象上。指向同步塊內另一個對象的引用根本不影響同步。它仍然在「舊」對象上同步。
這是非常糟糕的。同步最適用於最終班級成員。
現代的方法來創建一個線程安全的方式將對象在循環中使用的AtomicReference compareAndSet在行動(第15章)在戈茨的Java併發討論。這不會阻塞你的線程,並且提供比同步塊更高的性能。
private final AtomicReference<SomeObject> someObject = new AtomicReference<>();
void buildIt() {
SomeObject obj = new SomeObject();
SomeObject current = someObject.get(); //probably null, but doesn't matter
while (true) {
if (someObject.compareAndSet(current, obj))
break;
}
}
它不是那樣寫的。在我的情況下,類有用於同步塊的變量some_object,並且該變量在同一塊內被重新分配。 –
+1此處的關鍵是同步指的是對象,而不是參考。執行並分配'new'後,您仍然鎖定在舊對象上。此時新對象不鎖定。當同步塊退出時,舊對象的鎖定被釋放,並且如果沒有其他對它的引用,則它有資格使用gc。如果在實際的同步塊中有更多的代碼,並且它依賴鎖以某種方式轉移到新對象,那麼你可能會遇到問題。 –
謝謝吉姆。鎖在物體上而不是參考對我來說是有意義的。我很模糊的是,當變量引用的對象改變時,另一個線程是否會看到一個不同的解鎖對象並再次進入該塊,或者執行同步塊的機制阻止該事件發生? –