[英]Is this dictionary function thread-safe (ConcurrentHashMap+AtomicInteger)?
我需要寫一個非常簡單的字典,它只會附加。 字典將在許多線程之間共享。 當任何線程調用getId
我想確保始終為同一個單詞返回相同的id,即任何唯一單詞應該只有一個id。
現在顯然我可以同步訪問getId
方法,但這不是很有趣。 所以我想知道是否有一種無鎖方式來實現這一目標。
特別是,我想知道使用java.util.concurrent.ConcurrentHashMap#computeIfAbsent
的線程安全性。 ConcurrentMap
接口的javadoc說:
當多個線程嘗試更新(包括可能多次調用映射函數)時,默認實現可能會重試這些步驟。
根據該描述,我不清楚這是否意味着對於同一個鍵可能會多次調用映射函數?
如果是這種情況(即映射器可能被多次調用同一個鍵),那么我認為以下代碼很可能不是線程安全的,因為它可以為同一個鍵(即單詞)調用getAndIncrement
多次。
如果不是這樣,那么我認為以下代碼是線程安全的。 誰能確認一下?
public class Dictionary {
private final AtomicInteger index = new AtomicInteger();
private final ConcurrentHashMap<String, Integer> words =
new ConcurrentHashMap<>();
public int getId(final String word) {
return words.computeIfAbsent(word, this::newId);
}
private int newId(final String word) {
return index.getAndIncrement();
}
}
這保證是ConcurrentMap
Javadoc (強調我的)的線程安全:
在將對象作為鍵或值放入ConcurrentMap之前的線程中的操作發生在從另一個線程中的ConcurrentMap 訪問或刪除該對象之后的操作之前 。
ConcurrentHashMap
Javadoc有一個類似於你的例子:
通過使用LongAdder值並通過computeIfAbsent初始化,ConcurrentHashMap可用作可伸縮頻率映射(直方圖或多集的形式)。 例如,要向
ConcurrentHashMap<String,LongAdder> freqs
添加計數,可以使用freqs.computeIfAbsent(k -> new LongAdder()).increment();
雖然這使用computeIfAbsent
,但它應該類似於putIfAbsent
。
java.util.concurrent
包Javadoc談到“之前發生”:
Java語言規范的第17章定義了內存操作的先發生關系,例如共享變量的讀寫。 只有在讀取操作之前發生寫入操作時 ,一個線程的寫入結果才能保證對另一個線程的讀取可見。
語言規范說:
可以通過先發生關系來排序兩個動作。 如果一個動作發生在另一個動作之前,那么第一個動作在第二個動作之前可見並且在第
所以你的代碼應該是線程安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.