在Java中HashMap与ConcurrentHashMap

时间:2020-01-09 10:35:09  来源:igfitidea点击:

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使用单独的锁用于单独的存储桶,从而提供了很多更好的并发级别。