我煞費苦心地提出問題。我有以下片(Java)的代碼(僞)的:保持「顯而易見」的鎖定檢索或使用雙重檢查鎖定?
public SomeObject getObject(Identifier someIdentifier) {
// getUniqueIdentifier retrieves a singleton instance of the identifier object,
// to prevent two Identifiers that are equals() but not == (reference equals) in the system.
Identifier singletonInstance = getUniqueIdentifier(someIdentifier);
synchronized (singletonInstance) {
SomeObject cached = cache.get(singletonInstance);
if (cached != null) {
return cached;
} else {
SomeObject newInstance = createSomeObject(singletonInstance);
cache.put(singletonInstance, newInstance);
return newInstance;
}
}
}
基本上,它使一個識別符「獨特的」(參考值等於,如在==
),檢查高速緩衝存儲器,並且在一個高速緩存未命中的情況下,調用一個昂貴的方法(涉及調用外部資源和解析等),將其放入緩存中並返回。在這種情況下,同步的Identifier
避免了兩個equals()
而不是==
Identifier
對象被用來調用昂貴的方法,它將同時檢索相同的資源。
以上作品。我只是想知道,並且可能是微型優化,會改寫如下,它會採用更簡單的緩存檢索,並且雙重檢查鎖定是'安全'的(在線程安全中是安全的,沒有奇怪的競爭條件)並且'更多最優「(如減少不必要的鎖定和線程必須等待鎖定)?
public SomeObject getObject(Identifier someIdentifier) {
// just check the cache, reference equality is not relevant just yet.
SomeObject cached = cache.get(someIdentifier);
if (cached != null) {
return cached;
}
Identifier singletonInstance = getUniqueIdentifier(someIdentifier);
synchronized (singletonInstance) {
// re-check the cache here, in case of a context switch in between the
// cache check and the opening of the synchronized block.
SomeObject cached = cache.get(singletonInstance);
if (cached != null) {
return cached;
} else {
SomeObject newInstance = createSomeObject(singletonInstance);
cache.put(singletonInstance, newInstance);
return newInstance;
}
}
}
你可以說「只是測試它」或「只是做一個微標杆」,但測試的代碼多線程位是不是我的強項,我懷疑我能夠模擬現實的情況或準確的假競賽條件。再加上它會帶我半天,而寫一個SO問題只需要幾分鐘:)。
預警:[雙重檢查鎖定在Java中被破壞。](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html) – cHao 2011-03-08 14:44:19
cHao該論文描述了DCL之前的狀態Java5內存模型。在新的內存模型下,volatile的語義是固定的,以便DCL模式能夠正常工作。但是,使用封裝惰性的util始終是首選:https://labs.atlassian.com/wiki/display/CONCURRENT/LazyReference+and+ResettableLazyReference – 2011-03-08 22:13:31