Java HashMap 默认不同步。
如果我们在多个线程添加和删除键值对的并发应用程序中从 HashMap 添加/删除键值对,我们最终可能会导致映射状态不一致。
同步HashMap - ConcurrentHashMap
如果我们希望在并发环境中使用 Map,我们的首选应该始终是使用 ConcurrentHashMap类。ConcurrentHashMap通过设计支持并发访问它的键值对。
我们不需要执行任何另外的代码修改来启用地图同步。
请注意,从 ConcurrentHashMap获得的迭代器不会抛出 ConcurrentModificationException。
然而,迭代器被设计为一次只能被一个线程使用。
这意味着我们从 ConcurrentHashMap 获得的每个迭代器都设计为由单个线程使用,不应传递。
如果我们这样做,则不能保证一个线程会看到另一个线程执行的映射更改(无需从映射中获取新的迭代器)。
迭代器保证在创建时反映地图的状态。
示例:
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
public class HashMapExample
{
public static void main(String[] args) throws CloneNotSupportedException
{
ConcurrentHashMap<Integer, String> concurrHashMap = new ConcurrentHashMap<>();
//Put require no synchronization
concurrHashMap.put(1, "A");
concurrHashMap.put(2, "B");
//Get require no synchronization
concurrHashMap.get(1);
Iterator<Integer> itr = concurrHashMap.keySet().iterator();
//Using synchronized block is advisable
synchronized (concurrHashMap)
{
while(itr.hasNext()) {
System.out.println(concurrHashMap.get(itr.next()));
}
}
}
}
输出:
A B
同步HashMap - Collections.synchronizedMap()
Synchronized HashMap 的工作方式也与 ConcurrentHashMap 非常相似,但几乎没有区别。
SynchronizedHashMap一次只允许一个线程执行读/写操作,因为它的所有方法都声明为 synchronized 。ConcurrentHashMap允许多个线程在映射中的不同段上独立工作。
这允许 ConcurrentHashMap 中更高程度的并发,从而提高整个应用程序的性能。
两个类的迭代器都应该在synchronized块中使用,但是来自 SynchronizedHashMap 的迭代器是快速失败的。
ConcurrentHashMap 迭代器不是快速失败的。
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapExample
{
public static void main(String[] args) throws CloneNotSupportedException
{
Map<Integer, String> syncHashMap = Collections.synchronizedMap(new HashMap<>());
//Put require no synchronization
syncHashMap.put(1, "A");
syncHashMap.put(2, "B");
//Get require no synchronization
syncHashMap.get(1);
Iterator<Integer> itr = syncHashMap.keySet().iterator();
//Using synchronized block is advisable
synchronized (syncHashMap)
{
while(itr.hasNext()) {
System.out.println(syncHashMap.get(itr.next()));
}
}
}
}
输出:
A B
