关注△mikechen的架构笔记△,十余年BAT架构经验倾囊相授
ConcurrentHashMap是Java并发编程非常重要的容器,也是大厂重点考察,下面我就全面来详解ConcurrentHashMap@mikechen
ConcurrentHashMap
ConcurrentHashMap 是 Java 中一种线程安全的哈希表实现,主要用于多线程环境下的数据存取。
当需要在多线程环境中对集合(如:Map)进行并发操作时,ConcurrentHashMap 是比 Hashtable /或 synchronizedMap 更优的选择。
因为,与 Hashtable 使用全表锁定的方式不同,ConcurrentHashMap 通过锁分离、CAS ........等操作,实现了更高的并发度。
允许多个线程并发地读取、或更新哈希表的不同部分,从而在多线程环境中表现出更优的性能。
ConcurrentHashMap原理
如果你要更清楚ConcurrentHashMap 为什么性能更好,你需要更加深入的理解”ConcurrentHashMap 背后的底层实现“。
下面我重点谈谈ConcurrentHashMap 的底层实现原理,这里需要分别谈到:JDK1.7/JDK.18的实现。
ConcurrentHashMap(JDK.1.7)实现原理
在 Java 1.7 中,ConcurrentHashMap 使用了分段锁(Segmented) +分段锁(Locking)机制。
整体实现,如下图所示:
如下图所示:
1.数据结构
ConcurrentHashMap(1.7版本):由一个包含 Segment 数组的对象组成。
每个 Segment 是一个小型的、独立的哈希表,并有自己的一把锁,这样,每个 Segment 的数据可以在不同的线程中独立访问。
2.分段锁(Lock)机制
每个 Segment 维护其自己的锁,当线程访问某个特定的 Segment 时。
只有该 Segment 会被锁定,其他的 Segment 不受影响,这种机制允许多个线程同时访问不同的 Segment,从而提高并发性能。
虽然分段锁提高了并发性,但在大量数据分布不均的情况下,比如:比如所有数据都落在一个 Segment 中,可能会导致性能瓶颈。
所以,在ConcurrentHashMap(1.8版本),进行了改进。
ConcurrentHashMap(JDK.1.8)实现原理
在 Java 1.8 中,ConcurrentHashMap 进行了重大改进,放弃了分段锁机制,改用更细粒度的锁、和 CAS 操作。
并且,ConcurrentHashMap(JDK8),还参考了HashMap(JDK8)的实现,如下图所示:
ConcurrentHashMap 仍然使用 Node 数组(类似:HashMap),每个数组元素是一个 Node 链表或红黑树。
为了支持高并发,在 Java 8 中,ConcurrentHashMap 完全移除了分段锁的设计,转而使用更加细粒度的并发控制机制。
比如:Java 8 中的 ConcurrentHashMap 不再使用 Segment,而是采用了与 HashMap 类似的结构,即一个数组加链表、或红黑树的形式。
并且,ConcurrentHashMap 通过 CAS 操作(Compare-And-Swap)来实现高效的无锁插入。
比如:在进行 put 操作时,会先尝试用 CAS 来将数据插入到合适的位置,如果 CAS 操作成功,说明插入完成,否则,表示有冲突,可能需要进一步处理。
而且,ConcurrentHashMap 会对冲突的链表或树节点,使用 synchronized 进行锁定,而不是像 Java 7 中那样锁定整个 Segment。
所以,在多线程环境中,由于锁的使用更精细,线程之间的锁争用显著减少。
ConcurrentHashMap实战
这些改进,使得 ConcurrentHashMap 成为处理并发数据结构的一个更加高效且灵活的选择。
public class ConcurrentAccessExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newFixedThreadPool(3);
// 三个线程并发地更新 "apple" 的计数
for (int i = 0; i < 3; i++) {
executor.submit(() -> {
for (int j = 0; j < 1000; j++) {
map.merge("apple", 1, Integer::sum);
}
});
}
// 关闭线程池
executor.shutdown();
while (!executor.isTerminated()) {
// 等待所有任务完成
}
System.out.println("Final Apple count: " + map.get("apple"));
}
}
在这个例子中,多个线程同时访问和修改 ConcurrentHashMap,由于其内部的线程安全机制,即使在高并发情况下,ConcurrentHashMap 也能正确更新数据。
总之,ConcurrentHashMap 是 Java 中处理高并发情况下,线程安全问题的强大工具,熟悉其实现原理、和使用方式对编写高效的并发代码至关重要。
以上
最后送大家一个福利:
送我原创超30万字阿里架构师进阶专题合集。
以及给大家整理最全大厂Java面试题及答案详解,包含:Java、多线程、JVM、Spring、MySQL、Redis、中间件...等必考题答案详解。
需要以上架构专题&面试答案的同学,加我微信即可领取!
添加时备注:资料