在Java中HashMap与ConcurrentHashMap
Java中的ConcurrentHashMap是线程安全的Map实现,除了HashTable或者显式同步HashMap之外,它还提供了另一种在多线程环境中使用的替代方法。
Java中的HashMap不同步,因此线程安全性不高,但可提供更好的性能。在本文中,我们将看到Java中的HashMap和ConcurrentHashMap之间的区别。
在Java中HashMap与ConcurrentHashMap
1线程安全:
HashMap和ConcurrentHashMap之间的主要区别之一是ConcurrentHashMap是线程安全的,可以在并发环境中使用。
HashMap不是线程安全的,在多线程环境中共享HashMap的实例将产生不可预测的结果。
2如何完成同步:
HashMap可以使用Collections.synchronizedMap()方法从外部进行同步,该方法返回由指定地图支持的同步地图。请注意,以这种方式同步HashMap会在单个锁上同步HashMap的所有方法。在这篇文章中阅读有关HashMap同步的更多信息如何在Java中同步HashMap
ConcurrentHashMap已经是线程安全的,因此不需要外部同步。 ConcurrentHashMap通过仅锁定Map的一部分来提供更好的并发性。根据传递的并发级别将Map划分为多个分区。默认情况下,并发级别为16. 这意味着,如果所有线程正在访问Map的不同分区,则16个线程可以修改ConcurrentHashMap。
ConcurrentHashMap允许检索操作(例如get)与更新操作(例如put和remove)重叠,因为检索操作通常不会阻塞。这有助于提高ConcurrentHashMap的性能。
3迭代器故障快速或者故障安全
HashMap的"集合视图方法"返回的迭代器是快速失败的。如果在创建迭代器之后的任何时候都对结构进行了结构修改,则除了通过迭代器自己的remove方法之外,该迭代器将以任何其他方式进行修改,该迭代器将抛出ConcurrentModificationException。
由ConcurrentHashMap的"集合视图方法"返回的迭代器是故障安全的,并且如果在创建迭代器后随时对结构进行了修改,则不会引发ConcurrentModificationException。
这是一个示例,该示例显示了使用带有HashMap和ConcurrentHashMap的迭代器进行的迭代。
public class HashMapDemo { public static void main(String[] args) { // Creating HashMap Map<String, String> carMap = new HashMap<String, String>(); // Storing elements carMap.put("1", "Audi"); carMap.put("2", "BMW"); carMap.put("3", "Jaguar"); carMap.put("4", "Mini Cooper"); Set<String> carSet = carMap.keySet(); Iterator<String> itr = carSet.iterator(); while (itr.hasNext()) { String key = itr.next(); System.out.println("Key is " + key + " Value is " + carMap.get(key)); // removing value using HashMap's remove method if(key.equals("2")){ carMap.remove(key); } } } }
输出:
Key is 1 Value is Audi Key is 2 Value is BMW Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(Unknown Source) at java.util.HashMap$KeyIterator.next(Unknown Source) at com.theitroad.HashMapDemo.main(HashMapDemo.java:22)
如我们所见,当我们尝试使用迭代器对HashMap进行结构化修改时,会抛出ConcurrentModificationException异常。
就像在ConcurrentHashMap的情况下一样
public class FailSafeDemo { public static void main(String[] args) { Map<String, String> carMap = new ConcurrentHashMap<String, String>(); carMap.put("1", "Audi"); carMap.put("2", "BMW"); carMap.put("3", "Jaguar"); carMap.put("4", "Mini Cooper"); // iterating map Iterator<Map.Entry<String, String>> itr = carMap.entrySet().iterator(); while(itr.hasNext()) { Map.Entry<String, String> entry = itr.next(); System.out.println("Key is " + entry.getKey() + " Value is " + entry.getValue()); carMap.put("5", "Mercedes"); } System.out.println("Size- " + carMap.size()); } }
输出:
Key is 1 Value is Audi Key is 2 Value is BMW Key is 3 Value is Jaguar Key is 4 Value is Mini Cooper Key is 5 Value is Mercedes Size- 5
如我们所见,在迭代ConcurrentHashMap时,向其中添加了一个新元素,这不会导致抛出ConcurrentModificationException。
4允许为空
HashMap允许使用null值和null键。
ConcurrentHashMap不允许将null用作键或者值。
5性能
HashMap更快,因为它不同步。如果必须在多个线程之间共享HashMap实例,并且必须在外部进行同步,则与ConcurrentHashMap相比,HashMap的速度要慢一些,因为在这种情况下,整个HashMap是在单个锁上同步的,例如ConcurrentHashMap使用单独的锁用于单独的存储桶,从而提供了很多更好的并发级别。