4

我試圖追蹤競賽狀況,所有跡象似乎都指向ConcurrentHashMap.putIfAbsent()。是否有可能,如果兩個線程在具有相同密鑰的空映射上調用putIfAbsent(),這兩個線程都可以通過查找來查看密鑰不存在,那麼兩個線程都會嘗試添加它?由於某種原因,當我第一次開始使用putIfAbsent()時,我並不認爲這個調用需要同步。但是現在我看不出它是如何防止兩個線程在時機正確的情況下添加它們的值。我無法在生產之外重現這一點。需要使用同步操作的任何併發收集java.util.concurrent.ConcurrentHashMap.putIfAbsent是否需要在同步塊中?

感謝

+0

你能發佈一個代碼片段嗎?細節決定成敗。 – Tudor

回答

9

無。

這是通過設計和實際上鎖定集合對其他操作沒有影響。 (除非它們被鎖定)在這種情況下,它會使它們變慢。

是否有可能,如果2個線程的空地圖上調用的putIfAbsent()使用相同的密鑰既可以做他們的查詢看到,關鍵還不存在這樣兩個線程然後嘗試增加嗎?

兩者都可以嘗試,但只有一個會成功。兩個線程似乎不可能成功。

由於某種原因,當我第一次開始使用putIfAbsent()時,我並不認爲該調用需要同步。

它沒有。

但是現在我看不到如何防止兩個線程在時機正確的情況下添加它們的值。

它在代碼中執行CAS operation,這意味着只有一個操作可以成功,並且線程將知道哪一個操作。 CAS操作不需要鎖定,因爲它使用底層彙編指令來執行此操作。實際上,您通常會使用CAS操作來實現鎖定,而不是相反。

+0

而且我應該仍然期望對於能夠執行插入的線程,putIfAbsent調用返回null。而對於另一個線程putIfAbsent會返回其他線程值,使其進入地圖? – Brian

+0

@布萊恩是正確的,如果你做了get(),你會看到你期望的值。 –

3

是否有可能,如果2個線程調用putIfAbsent一個空的地圖上使用相同的密鑰既可以做他們的查詢看到,關鍵還不存在這樣兩個線程然後嘗試增加嗎?

不按照爲putIfAbsent()的文檔:

如果指定鍵已經不再與某個值相關聯,它與給定值相關聯。這相當於

if (!map.containsKey(key)) 
    return map.put(key, value); 
else 
    return map.get(key); 

除了以原子執行的操作。

這意味着兩個線程都不可能嘗試插入鍵值對。