簡體   English   中英

這個字典是否是線程安全的(ConcurrentHashMap + AtomicInteger)?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM