[英]Is an assignment inside ConcurrentHashMap.computeIfAbsent threadsafe?
[英]Why does ConcurrentHashMap.computeIfAbsent() increment the counter for an already present key?
運行此示例代碼(來自 Cay Horstmann)
ConcurrentHashMap<String,LongAdder> counts = new ConcurrentHashMap<>();
for (String key : "Row, row, row a boat".split("\\PL+"))
counts.computeIfAbsent(key, k -> new LongAdder()).increment();
System.out.println(counts);
輸出是
{a=1, Row=1, row=2, boat=1}
看到row=2
我很驚訝,因為我預計 computeIfAbsent() 只會在它找到第一個“行”而不是第二個“行”時增加。
counts.computeIfAbsent(key, k -> new LongAdder())
整個表達式可以采用以下兩種方式之一:
key
已經在counts
映射中。 在這種情況下,“計算機”函數( k -> new LongAdder()
)被完全忽略; 它根本沒有運行。 而是返回與該鍵關聯的值。
key
不在counts
映射中。 在這種情況下,“計算機”函數執行一次,它返回的值現在與鍵相關聯。
換句話說,它等同於:
LongAdder result;
if (counts.containsKey(key)) result = counts.get(key);
else {
result = new LongAdder();
counts.put(key, result);
}
return result;
如果您使用正確的實現(例如ConcurrentHashMap
),這是一個拗口的,可能效率較低且可能不是原子的,而.computerIfAbsent
可以是原子的。
線索如下:然后你調用.increment()
這個結果,不管我們是在#1 case 還是#2 case 。
換句話說:
看到第一個“行”, computeIfAbsent
最終執行 lambda,因此運行類似counts.put(k, new LongAdder())
的東西,然后你調用.increment()
。
接下來,看到第二個“行”, computeIfAbsent
最終等同於counts.get(key)
,然后您調用.increment()
。 這與我們看到第一行時制作的 LongAdder 相同,因此這是您第二次在其上調用increment()
。
增加任何東西的不是computeIfAbsent
。 是.increment()
增加一些東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.