[英]ConcurrentHashMap vs Synchronized HashMap
在HashMap
和ConcurrentHashMap
上使用包裝類SynchronizedMap
什么區別?
它是否只能在迭代時修改HashMap
( ConcurrentHashMap
)?
同步HashMap
:
每個方法都使用對象級鎖進行同步。 所以synchMap 上的get 和put 方法需要一個鎖。
鎖定整個集合是一種性能開銷。 當一個線程持有鎖時,沒有其他線程可以使用該集合。
ConcurrentHashMap
是在 JDK 5 中引入的。
沒有對象級別的鎖定,鎖定的粒度要細得多。 對於ConcurrentHashMap
,鎖定可能處於哈希圖存儲桶級別。
較低級別鎖定的效果是您可以擁有並發的讀取器和寫入器,這對於同步集合是不可能的。 這導致更多的可擴展性。
如果一個線程試圖修改它而另一個正在迭代它,則ConcurrentHashMap
不會拋出ConcurrentModificationException
。
這篇文章Java 7: HashMap vs ConcurrentHashMap是一本很好的讀物。 強烈推薦。
簡短的回答:
這兩個映射都是Map
接口的線程安全實現。 ConcurrentHashMap
是為了在需要高並發的情況下實現更高的吞吐量而實現的。
Brian Goetz 關於ConcurrentHashMap
背后的想法的文章非常好讀。 強烈推薦。
ConcurrentHashMap
是線程安全的,無需同步整個地圖。 當使用鎖完成寫入時,讀取可以非常快地發生。
我們可以同時使用 ConcurrentHashMap 和 SynchronisedHashmap 來實現線程安全。 但是如果你看看他們的架構,就會有很多不同。
它將在對象級別保持鎖定。 所以如果你想執行像 put/get 這樣的任何操作,那么你必須先獲取鎖。 同時,不允許其他線程執行任何操作。 因此,一次只有一個線程可以對此進行操作。 所以這里的等待時間會增加。 可以說和 ConcurrentHashMap 相比,性能比較低。
它將在段級別保持鎖定。 它有 16 個段,並且默認保持並發級別為 16。 所以一次可以有 16 個線程可以操作 ConcurrentHashMap。 而且,讀操作不需要鎖。 因此,任意數量的線程都可以對其執行 get 操作。
如果thread1想在segment 2執行put操作,thread2想在segment 4執行put操作,這里是允許的。 意味着,16 個線程可以同時對 ConcurrentHashMap 執行更新(放置/刪除)操作。
這樣在這里等待的時間就會少一些。 因此性能相對優於同步哈希圖。
兩者都是HashMap的同步版本,核心功能和內部結構不同。
ConcurrentHashMap由內部段組成,從概念上可以將其視為獨立的 HashMap。 所有這些段都可以在高並發執行中由單獨的線程鎖定。 因此,多個線程可以從 ConcurrentHashMap 獲取/放置鍵值對,而不會相互阻塞/等待。 這是為了更高的吞吐量而實施的。
然而
Collections.synchronizedMap() ,我們得到 HashMap 的同步版本,它以阻塞方式訪問。 這意味着如果多個線程嘗試同時訪問 synchronizedMap,它們將被允許以同步方式一次獲取/放置一個鍵值對。
ConcurrentHashMap
使用稱為lock stripping
的細粒度鎖定機制來允許更大程度的共享訪問。 因此,它提供了更好的並發性和可伸縮性。
此外,為ConcurrentHashMap
返回的迭代器是弱一致的,而不是 Synchronized HashMap 使用的快速失敗技術。
SynchronizedMap
上的方法持有對象上的鎖,而在ConcurrentHashMap
有一個“鎖條帶”的概念,其中鎖被持有在內容的桶上。 從而提高了可擴展性和性能。
並發哈希映射:
1)兩個map都是Map接口的線程安全實現。
2) ConcurrentHashMap 是為了在需要高並發的情況下實現更高的吞吐量。
3) 對象級別沒有鎖定。
同步哈希映射:
1) 每個方法都使用對象級鎖進行同步。
ConcurrentHashMap允許並發訪問數據。 整個地圖被分成幾段。
讀取操作即。 即使在段級別, get(Object key)
也不同步。
但是寫操作即。 remove(Object key), get(Object key)
在段級別獲取鎖。 只有整個地圖的一部分被鎖定,其他線程仍然可以從除了鎖定的一個段之外的各個段讀取值。
另一方面, SynchronizedMap在對象級別獲取鎖。 無論操作(讀/寫)如何,所有線程都應等待當前線程。
ConcurrentHashMap 與 Synchronized HashMap 的簡單性能測試。 測試流程是在一個線程中調用put
並在Map
上的三個線程中同時調用get
。 正如@trshiv 所說,ConcurrentHashMap 具有更高的吞吐量和速度,其無鎖讀取操作。 結果是當操作次數超過10^7
,ConcurrentHashMap 比 Synchronized HashMap 快2x
倍。
同步HashMap
2.空鍵或值- 允許空作為鍵或值。
3.並發修改異常——同步映射返回的迭代器拋出並發修改異常
並發哈希映射
1.鎖定機制——鎖定部分,Concurrent hashmap 允許並發讀寫。 所以性能相對來說比同步地圖好
2.空鍵或值- 它不允許空作為鍵或值。 如果你使用它會拋出java.lang。 運行時出現NullPointerException 。
3.並發修改異常- 它不會拋出並發修改異常。
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Ex_ConcurrentHashMap {
public static void main(String[] args) {
Map<String, String> map = new ConcurrentHashMap<>();
map.put("one", "one");
map.put("two", "two");
map.put("three", "three");
System.out.println("1st map : "+map);
String key = null;
for(Map.Entry<String, String> itr : map.entrySet())
{
key = itr.getKey();
if("three".equals(key))
{
map.put("FOUR", "FOUR");
}
System.out.println(key+" ::: "+itr.getValue());
}
System.out.println("2nd map : "+map);
//map.put("FIVE", null);//java.lang.NullPointerException
map.put(null, "FIVE");//java.lang.NullPointerException
System.out.println("3rd map : "+map);
}
}
同步 HashMap 示例
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class Ex_Synchronizedmap {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("one", "one");
map.put("two", "two");
map.put("three", "three");
map.put("FOUR", null);
map.put(null, "FIVE");
System.out.println("map : "+map);
Map<String, String> map1 =
Collections.synchronizedMap(map);
System.out.println("map1 : "+map1);
String key = null;
for(Map.Entry<String, String> itr : map1.entrySet())
{
key = itr.getKey();
if("three".equals(key))
{
map1.put("ABC", "ABC");
}
System.out.println(key+" ::: "+itr.getValue());
}
System.out.println("New Map :: "+map1);
Iterator<Entry<String, String>> iterator = map1.entrySet().iterator();
int i = 0;
while(iterator.hasNext())
{
if(i == 1)
{
map1.put("XYZ", "XYZ");
}
Entry<String, String> next = iterator.next();
System.out.println(next.getKey()+" :: "+next.getValue());
i++;
}
}
}
根據java doc的
Hashtable 和 Collections.synchronizedMap(new HashMap()) 是同步的。 但是 ConcurrentHashMap 是“並發的”。
並發集合是線程安全的,但不受單個排除鎖的控制。
在 ConcurrentHashMap 的特殊情況下,它安全地允許任意數量的並發讀取以及可調整數量的並發寫入。 當您需要通過單個鎖阻止對集合的所有訪問時,“同步”類可能很有用,但代價是可擴展性較差。
在期望多個線程訪問公共集合的其他情況下,“並發”版本通常更可取。 當集合未共享或僅在持有其他鎖時才可訪問時,最好使用非同步集合。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.