面试官刁难:ConcurrentHashMap的并发度?90%的人答不全!

软件求生 2025-03-24 09:39:34



小米(也就是我啦!)最近在帮朋友小张模拟 Java 社招面试。小张是个资深开发,前几天面试了一家大厂,回来愁眉苦脸。

“怎么了?”我好奇地问。

“面试官问了个问题:ConcurrentHashMap 是什么?ConcurrentHashMap 的并发度是什么?”小张叹了口气,“我感觉答得不太好……”

“这个问题很重要啊,尤其是在高并发场景下,ConcurrentHashMap 是 Java 开发必备的武器!”我拍了拍小张的肩膀,“今天就让我给你系统讲解一下,保证你下次面试轻松拿捏!”

什么是 ConcurrentHashMap?

在 Java 里,多线程环境下如果要存储键值对,大家首先想到的可能是 HashMap,但 HashMap 在并发场景下是不安全的,可能会引发数据不一致,甚至出现死循环(JDK 7 的 HashMap 发生扩容时可能会导致链表形成环,遍历时无限循环)。

“那用 Hashtable 呢?”小张问。

Hashtable 是线程安全的,但它的并发性能很差,因为它直接对整个数据结构加了 synchronized 锁,导致多个线程同时操作时变成串行化,效率极低。

于是,Java 1.5 引入了 ConcurrentHashMap,它通过分段锁(JDK 7)或者 CAS+红黑树(JDK 8)的方式,实现了高效并发读写,解决了 Hashtable 过于保守的同步策略,也避免了 HashMap 线程不安全的问题。

简单来说,ConcurrentHashMap 是 Java 提供的一个高效线程安全的 HashMap 实现!

ConcurrentHashMap 的并发度是什么?

“那 ConcurrentHashMap 的并发度是什么意思?”小张继续问。

并发度(Concurrency Level)指的是可以同时进行并发操作的最大线程数。在 JDK 7 及之前的实现中,ConcurrentHashMap 采用分段锁(Segment),默认并发度是 16,也就是说,最多可以有 16 个线程同时修改不同的段(Segment),提高了吞吐量。

JDK 8 之后移除了 Segment,采用了更高效的 CAS + synchronized 方案,但仍然支持高并发操作。

我画了个简单的对比图,让小张更直观地理解:

JDK 7 的 ConcurrentHashMap(分段锁)

在 JDK 7 及以前,ConcurrentHashMap 的内部结构是这样的:

底层采用了 Segment 数组,每个 Segment 本质上是一个小型的 Hashtable,每个 Segment 内部用 ReentrantLock 加锁。

核心思想:

ConcurrentHashMap 由多个 Segment 组成,每个 Segment 维护一个自己的 table(类似于小型 Hashtable)。

多线程写入时,只会锁定某个 Segment,而不会锁住整个 ConcurrentHashMap,提高并发能力。

默认分 16 个 Segment,所以并发度是 16,即最多可以有 16 个线程同时操作不同的 Segment。

JDK 8 的 ConcurrentHashMap(CAS + synchronized)

到了 JDK 8,Segment 被移除,数据结构变得更加简单,采用了数组 + 链表 + 红黑树的结构,并使用了CAS + synchronized 来保证线程安全。

主要原理是:

读操作无锁化:大多数情况下,读操作不会加锁,而是直接读取 volatile 变量。

写操作使用 CAS(Compare-And-Swap)+ synchronized:先尝试使用 CAS 修改数据,如果失败(说明有并发冲突),则退化为 synchronized 加锁。

链表转红黑树:当链表长度超过 8 时,会转换为红黑树,提高查询效率。

JDK 8 的优化点:

读操作用 volatile 变量保证可见性,减少锁的使用。

写操作优先用 CAS,只有在竞争激烈时才会使用 synchronized。

采用红黑树优化链表查询,提高性能。

面试答题技巧:如何回答 ConcurrentHashMap 的并发度?

标准回答思路:

1、什么是 ConcurrentHashMap?

ConcurrentHashMap 是 Java 提供的线程安全的 HashMap,实现了高效的并发访问。

2、ConcurrentHashMap 的并发度是什么?

JDK 7 及以前,采用 Segment(分段锁)机制,并发度默认是 16,即最多可以有 16 个线程同时写入不同的 Segment。

JDK 8 之后,去掉了 Segment,改为 CAS + synchronized 机制,并使用 Node + 红黑树 结构,提高了并发性能。

3、ConcurrentHashMap 与 HashMap/Hashtable 的区别?

HashMap:非线程安全,多线程环境可能会出现死循环。

Hashtable:线程安全,但加锁粒度大,性能低。

ConcurrentHashMap:线程安全,并发性能好,读操作无锁,写操作用 CAS + synchronized。

END

小张听完后,豁然开朗:“原来 ConcurrentHashMap 还有这么多讲究!下次面试官再问,我一定能答得完美!”

“当然啦!”我笑着说,“记住,并发编程的本质是如何高效、安全地共享数据,ConcurrentHashMap 只是其中一个重要工具,理解它的底层原理,比死记硬背更有价值!”

你在面试时遇到过 ConcurrentHashMap 相关的问题吗?欢迎留言讨论!

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!

0 阅读:0

软件求生

简介:从事软件开发,分享“技术”、“运营”、“产品”等。