簡體   English   中英

我們可以為每個條目而不是ConcurrentHashMap使用Synchronized嗎?

[英]Can we use Synchronized for each entry instead of ConcurrentHashMap?

這就是問題所在:我們想要一個哈希表,其條目是線程安全的。

假設我有一個<String, Long>的哈希表,並且我想安全地增加其中一個條目線程的值:可以嗎?

HashMap<String , Long> hashTable = new HashMap<String, Long>();

然后,每當我想增加一個條目時:

Synchronized (hashTable.get("key"))
{
    Long value = hashTable.get("key");
    value++;
    hashTable.put("key", value);
}

我認為它比ConcurrentHashMap更好,因為它僅鎖定一個條目,而不像ConcurrentHashMap使用存儲桶並將一組條目鎖定在一起。

更重要的是,我不知道如何安全地使用COncurrenHashMap對其進行遞增。 例如,我認為以下代碼不正確:

 ConcurrentHashMap<String , Long> hashTable = new ConcurrentHashMap<String, Long>();


 Long value = hashTable.get("key");
 value++;
 hashTable.put("key", value);

我認為這是不正確的,因為兩個線程可以一個接一個地讀取鍵,然后一個接一個地寫入鍵,最終得到錯誤的值。

你們覺得怎么樣?

您提出的方法不是線程安全的,因為初始hashTable.get()操作(通過該操作獲取您要在其上進行同步的對象)相對於其他線程put()本身與之相關聯的值本身並不同步。相同的鍵。 此外,您的代碼不考慮將新值添加到映射或從映射中刪除鍵的可能性(所謂的“結構修改”)。 如果可能發生這種情況,無論鍵如何,那么這些動作都必須相對於對地圖的所有其他訪問進行同步。

沒錯,但是, ConcurrentHashMap也不能解決這些問題。 就其提供的單個操作而言,它是線程安全的,其中包括Map本身未定義的某些操作,但是必須作為同步單元執行的一系列操作仍需要通過同步進行保護。

我建議使用一種稍微不同的方法:將ConcurrentHashMapAtomicLong ,該變量是可變的,而不是Long

ConcurrentHashMap<String, AtomicLong> map;

然后,即使您不確定該鍵在映射中是否已有條目,也要更新鍵的值,請執行以下操作:

AtomicLong value = map.putIfAbsent(key, new AtomicLong(0));
long updatedValue = value.incrementAndGet();

putIfAbsent()可確保不會因沖突的put操作而破壞值對象。 使用AtomicLong避免了將多個操作聯合同步的需要,因為只需要一次映射訪問-檢索到的值將由所有訪問它的線程共享,並且自身可以原子更新,而無需進一步訪問映射。

如果可以確定該映射已經具有給定鍵的映射,則只需執行以下操作:

AtomicLong value = map.get(key);
long updatedValue = value.incrementAndGet();

一種或另一種方式,我認為這是您所描述和隱含的操作中可以做的最好的事情。

更新:

您甚至可以考慮將這兩種方法結合起來:

AtomicLong value = map.get(key);

if (value == null) {
    value = map.putIfAbsent(key, new AtomicLong(0));
}

long updatedValue = value.incrementAndGet();

假定相對很少有給定密鑰沒有映射,並且在這種情況下避免創建新的AtomicLong 如果未找到映射,則必須第二次訪問該映射以確保存在映射並獲取相應的值,但是如果要避免同步,此處仍然需要putIfAbsent() ,因為可能有兩個線程都試圖在大約同一時間為同一鍵添加一個映射。 當需要添加新條目時,這樣做的成本更高,但是平均而言,它的成本可能比我的第一個建議要低。 但是,與任何性能問題一樣,必須進行測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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