ConcurrentHashMap最全详解(含JDK1.7和1.8原理剖析)

createh54周前 (02-14)技术教程15

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 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 中处理高并发情况下,线程安全问题的强大工具,熟悉其实现原理、和使用方式对编写高效的并发代码至关重要。

本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》里面。

相关文章

jdk版本的选择(推荐1.8)_jdk版本哪个好

对java新手来说,选择jdk的版本也是个头晕的事情,今天小拿就给大家讲讲。内容包括1.jdk从1.5到1.11,选哪个最好2.jdk和jre的区别一、jdk版本选择jdk是java开发工具包,除了运...

Java 中 ConcurrentHashMap 1.7 和 1.8 之间有哪些区别?

在初次接触 ConcurrentHashMap 时,许多同学难免会对它高并发环境下的设计原理心生好奇。要弄清它在不同版本之间究竟有何差异,就需要先探究底层原理的“前世今生”。本文将聚焦 Java 1....

Jdk1.8版本的下载,安装和环境变量配置

1.Jdk下载首先在官网上下载Jdk的安装包官网网址:[https://www.oracle.com/java/technologies/javase-downloads.html]下载1.8版本,使...

关于Java8的精心总结

前言 最近公司里比较新的项目里面,看到了很多关于java8新特性的用法,由于之前自己对java8的新特性不是很了解也没有去做深入研究,所以最近就系统的去学习了一下,然后总结了一篇文章第一时间和大家分享...

Java 8 新特性探秘:Lambda 表达式、Stream API 和 Optional 的深度解析

一、引言Java 8 的出现为开发者带来了诸多强大的新特性,其中 Lambda 表达式、Stream API 和 Optional 更是备受瞩目。这些新特性极大地提高了编程效率和代码的可读性,为 Ja...