簡體   English   中英

Java中的ConcurrentHashMap?

[英]ConcurrentHashMap in Java?

在Java中使用ConcurrentHashMap什么用? 它有什么好處? 它是如何工作的? 示例代碼也很有用。

重點是提供線程安全的HashMap實現。 多個線程可以讀取和寫入它,而不會接收過時或損壞的數據。 ConcurrentHashMap提供了自己的同步,因此您不必顯式同步對它的訪問。

ConcurrentHashMap另一個特性是它提供了putIfAbsent方法,如果指定的鍵不存在,它將以原子方式添加映射。 請考慮以下代碼:

ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>();

// some stuff

if (!myMap.contains("key")) {
  myMap.put("key", 3);
}

此代碼不是線程安全的,因為另一個線程可以在對contains的調用和put調用之間添加"key"映射。 正確的實施將是:

myMap.putIfAbsent("key", 3);

ConcurrentHashMap允許並發訪問地圖。 HashTables也提供對地圖的同步訪問,但您的整個地圖都被鎖定以執行任何操作。

ConcurrentHashMap背后的邏輯是your entire table is not getting locked ,只有部分[ segments ]。 每個細分都管理自己的HashTable。 鎖定僅適用於更新。 在檢索的情況下,它允許完全並發。

讓我們將四個線程同時在一個容量為32的映射上工作,該表被分成四個段,每個段管理一個容量哈希表。 該集合默認維護一個包含16個段的列表,每個段用於保護(或鎖定)地圖的單個存儲桶。

在此輸入圖像描述

這實際上意味着16個線程可以一次修改集合。 使用可選的concurrencyLevel構造函數參數可以增加此並發級別。

public ConcurrentHashMap(int initialCapacity,
                         float loadFactor, int concurrencyLevel)

正如另一個答案所述,ConcurrentHashMap提供了與put類似的新方法putIfAbsent() ,除非鍵存在時不會覆蓋該值。

private static Map<String,String> aMap =new ConcurrentHashMap<String,String>();

if(!aMap.contains("key"))
   aMap.put("key","value");

新方法也更快,因為它避免了如上所述的double traversing contains方法必須定位段並迭代表以找到鍵,並且put方法必須再次遍歷存儲桶並放入密鑰。

實際上,最大的功能區別在於,當您使用它時,當其他人更改它時,它不會拋出異常和/或最終損壞。

對於常規集合,如果另一個線程在您訪問它時(通過迭代器)添加或刪除元素,則會拋出異常。 ConcurrentHashMap允許他們進行更改並且不會停止您的線程。

請注意,它不會對從一個線程到另一個線程的更改的時間點可見性做出任何形式的同步保證或承諾。 (它有點像讀取提交的數據庫隔離,而不是同步映射,其行為更像是可序列化的數據庫隔離。(舊學校行鎖定SQL可序列化,而不是Oracle-ish multiversion serializable :))

我所知道的最常見的用途是在App Server環境中緩存不可變的派生信息,其中許多線程可能正在訪問同一個東西,如果兩個碰巧計算相同的緩存值並將它放兩次因為它們交錯並不重要等等(例如,它在Spring WebMVC框架內廣泛使用,用於保存運行時派生的配置,如從URL到Handler方法的映射。)

它可以用於記憶:

import java.util.concurrent.ConcurrentHashMap;
public static Function<Integer, Integer> fib = (n) -> {
  Map<Integer, Integer> cache = new ConcurrentHashMap<>();
  if (n == 0 || n == 1) return n;
  return cache.computeIfAbsent(n, (key) -> HelloWorld.fib.apply(n - 2) + HelloWorld.fib.apply(n - 1));
};

1.ConcurrentHashMap是線程安全的,即一次可以由單個線程訪問代碼。

2.ConcurrentHashMap同步或鎖定Map的某個部分。 為了優化ConcurrentHashMap的性能,Map根據並發級別划分為不同的分區。 這樣我們就不需要同步整個Map對象了。

3.Default並發級別為16,因此映射分為16個部分,每個部分由不同的鎖管理,這意味着16個線程可以運行。

4.ConcurrentHashMap不允許NULL值。 所以在ConcurrentHashMap中鍵不能為null。

大家好,今天我們討論了ConcurrentHashMap。
什么是ConcurrentHashMap?

ConcurrentHashMap是它在java 1.5中引入的一個類,它實現了ConcurrentMap以及Serializable接口。 ConcurrentHashMap在處理多個Theading時增強了HashMap。 正如我們所知,當應用程序具有多個線程時,HashMap不是一個好的選擇,因為會出現性能問題。

ConcurrentHashMap有一些關鍵點。

  • ConcurrentHashMap的Underling數據結構是HashTable。
  • ConcurrentHashMap是一個類,該類是線程安全的,它意味着多個線程可以訪問單個線程對象而不會出現任何復雜情況。
  • ConcurretnHashMap對象根據並發級別划分為多個段。
  • ConcurrentHashMap的默認並發級別為16。
  • 在ConcurrentHashMap中,任意數量的Thread都可以執行檢索操作,但是對於對象中的更新,Thread必須鎖定線程想要操作的特定Segment。
  • 這種類型的鎖定機構稱為段鎖定或鏟斗鎖定。
  • 在ConcurrentHashMap中,一次執行16個更新操作。
  • ConcurrentHashMap中無法插入空值。

這是ConcurrentHashMap構造。

  1. ConcurrentHashMap m = new ConcurrentHashMap();:使用默認初始容量(16),加載因子(0.75)和concurrencyLevel(16)創建一個新的空映射。

  2. ConcurrentHashMap m = new ConcurrentHashMap(int initialCapacity);:使用指定的初始容量創建一個新的空映射,並使用默認加載因子(0.75)和concurrencyLevel(16)。

  3. ConcurrentHashMap m = new ConcurrentHashMap(int initialCapacity,float loadFactor);:使用指定的初始容量和加載因子以及默認的concurrencyLevel(16)創建一個新的空映射。

  4. ConcurrentHashMap m = new ConcurrentHashMap(int initialCapacity,float loadFactor,int concurrencyLevel);:使用指定的初始容量,加載因子和並發級別創建一個新的空映射。

  5. ConcurrentHashMap m = new ConcurrentHashMap(Map m);:創建一個與給定地圖具有相同映射關系的新地圖。

ConcurretHashMap有一個名為putIfAbsent()的方法; 該方法是防止存儲重復密鑰請參考下面的例子。

    import java.util.concurrent.*; 

     class ConcurrentHashMapDemo { 
     public static void main(String[] args) 
     { 
         ConcurrentHashMap m = new ConcurrentHashMap(); 
          m.put(1, "Hello"); 
          m.put(2, "Vala"); 
          m.put(3, "Sarakar"); 

         // Here we cant add Hello because 1 key 
         // is already present in ConcurrentHashMap object 

            m.putIfAbsent(1, "Hello"); 

         // We can remove entry because 2 key 
         // is associated with For value 

            m.remove(2, "Vala"); 

        // Now we can add Vala

            m.putIfAbsent(4, "Vala"); 


            System.out.println(m); 
      } 
}  

暫無
暫無

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

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