章
目
录
Java HashMap在默认情况下不是同步的。如果在多个线程添加和删除键值对的并发应用程序中向HashMap添加/删除键值对,可能会导致不一致的映射状态。了解如何同步一个HashMap以及与ConcurrentHashMap之间的区别。
1.ConcurrentHashMap类
如果我们希望在并发环境中使用Map,我们的首选应该始终是使用ConcurrentHashMap类。ConcurrentHashMap通过设计支持对其键值对的并发访问。我们不需要执行任何额外的代码修改来启用Map上的同步。
请注意,从ConcurrentHashMap获得的迭代器不会引发ConcurrentModificationException。但是,迭代器被设计为一次只能由一个线程使用。这意味着我们从ConcurrentHashMap获取的每个迭代器都被设计为由单个线程使用,不应传递给其他线程。
如果这样做,不能保证一个线程将看到另一个线程执行的map更改(除非从map获取新的迭代器)。迭代器保证反映其创建时的map状态。
让我们来看一个使用ConcurrentHashMap的示例。
ConcurrentHashMap<Integer, String> concurrHashMap = new ConcurrentHashMap<>();
//put不需要同步
concurrHashMap.put(1, "A");
concurrHashMap.put(2, "B");
//get不需要同步
concurrHashMap.get(1);
Iterator<Integer> itr = concurrHashMap.keySet().iterator();
//建议使用同步块
synchronized (concurrHashMap) {
while (itr.hasNext()) {
System.out.println(concurrHashMap.get(itr.next()));
}
}
2. Collections.synchronizedMap()
同步HashMap与ConcurrentHashMap非常类似,但有一些区别。
同步HashMap允许一次只有一个线程执行读/写操作,因为它的所有方法都声明为同步的。而ConcurrentHashMap允许多个线程独立地在Map中的不同段上工作。这允许ConcurrentHashMap具有更高程度的并发性,从而提高了应用程序的整体性能。
来自这两个类的迭代器应该在同步块内使用,但来自同步HashMap的迭代器是fail-fast的。ConcurrentHashMap的迭代器不是fail-fast的。
Map<Integer, String> syncHashMap = Collections.synchronizedMap(new HashMap<>());
//put 不需要同步
syncHashMap.put(1, "A");
syncHashMap.put(2, "B");
//get不需要同步
syncHashMap.get(1);
Iterator<Integer> iterator = syncHashMap.keySet().iterator();
//建议使用同步块
synchronized (syncHashMap) {
while (iterator.hasNext()) {
System.out.println(syncHashMap.get(iterator.next()));
}
}
3. 同步HashMap和ConcurrentHashMap之间的区别
让我们识别一下这两个版本的地图之间的一些区别,以便我们可以决定在哪种情况下选择哪种Map。
- 在ConcurrentHashMap中,多个线程可以添加/删除键值对,而在同步HashMap的情况下,只有一个线程可以进行更改。这导致ConcurrentHashMap具有更高程度的并发性。
- 在ConcurrentHashMap中,不需要对Map加锁来读取值,检索操作将返回最近完成的插入操作插入的值。在SynchronizedHashMap中,读操作也需要加锁。
- 如果一个线程尝试在另一个线程迭代时修改ConcurrentHashMap,ConcurrentHashMap不会引发ConcurrentModificationException。迭代器反映其创建时的Map状态。SynchronizedHashMap返回的迭代器在并发修改时会快速失败。
4.结论
根据上述论点,我们可以得出结论,如果我们必须创建新的Map,那么使用ConcurrentHashMap始终是更好的选择。当我们有现有的Map实例并希望对其进行同步时,可以使用Collections.synchronizedMap()。
请提出与在Java中同步HashMap相关的问题。