ConcurrentHashMap 原理分析
ConcurrentHashMap
是 Java 中提供的一个线程安全的哈希表。相比于 Hashtable
和同步包装的 HashMap
(通过 Collections.synchronizedMap
获得),ConcurrentHashMap
提供了更高的并发性能。
分段锁(Segmentation)
在 Java 7 及之前,ConcurrentHashMap
使用了分段锁的概念,通过将内部数据分为一段一段(Segment),来减少锁的竞争。每个 Segment 维护了一个哈希表,并且每个 Segment 是独立锁定的。当进行插入、删除和更新操作时,只需要锁定相关的 Segment,而不需要锁定整个哈希表。
锁粒度进一步细化(Java 8)
在 Java 8 中,ConcurrentHashMap
的实现被进一步优化。Java 8 放弃了原有的 Segment 方式,转而使用了一种基于节点的锁机制,这种机制进一步提高了并发性。主要改进包括:
- 使用了一种称为“synchronized”和“CAS”(比较并交换)操作的机制来管理对单个桶(bucket)的写入。
- 读操作可以完全并行,因为它们不需要锁定。只有在写入的时候,才会锁定相关的桶,这减少了锁的范围和锁竞争。
- 链表转换为红黑树:为了改善在高哈希碰撞情况下的性能,链表结构被动态地替换为红黑树结构。
ConcurrentHashMap 使用实践
创建 ConcurrentHashMap
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
常用方法
put(key, value)
:将指定的值与此映射中的指定键关联。get(key)
:返回指定键所映射的值。remove(key)
:从此映射中移除键的映射关系。putIfAbsent(key, value)
:如果指定的键尚未与某个值关联,则将其与给定值关联。computeIfAbsent(key, mappingFunction)
:如果指定键的值为 null,尝试使用给定的映射函数计算其值。forEach(action)
:对ConcurrentHashMap
的每个元素执行给定的操作。
示例代码
ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();
chm.put(1, "Java");
chm.put(2, "Python");
chm.put(3, "Go");
String value = chm.get(1); // "Java"
chm.forEach((key, val) -> System.out.println(key + " => " + val));
String result = chm.computeIfAbsent(4, k -> "JavaScript");
System.out.println(result); // "JavaScript"
并发操作
由于 ConcurrentHashMap
是为高并发环境设计的,你可以在多个线程中安全地执行更新操作,而不需要外部同步。
ExecutorService executor = Executors.newFixedThreadPool(2);
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
Runnable task = () -> {
map.putIfAbsent(Thread.currentThread().getName(), "value");
};
executor.submit(task);
executor.submit(task);
executor.shutdown();
在上面的例子中,即使多个线程尝试更新 ConcurrentHashMap
,putIfAbsent()
方法保证了每个键只被赋值一次。
注意事项
- 虽然
ConcurrentHashMap
的读取操作非常快,但写入操作可能会稍微慢一些,因为它们涉及同步。 - 在迭代元素时,迭代器只能反映
ConcurrentHashMap
在迭代器创建时或在迭代开始时的状态。 ConcurrentHashMap
不允许使用 null 键或 null 值,因为多个 null 值可能导致无法区分返回值是 map 中的一个条目,还是 map 中没有该键。ConcurrentHashMap
提供了一系列原子操作,这意味着你不需要用同步来组合多个方法调用。
ConcurrentHashMap
是解决并发编程中的共享资源问题的强大工具。恰当使用它,可以在多线程环境下安全高效地管理共享的可变数据。