之前分享过一期HashMap的面试题,然后有个小伙伴私信我说,他遇到了一个ConcurrentHashMap的问题不知道怎么回答。

于是,就有了这一期的内容!!

我是Mic,一个工作了14年的Java程序员,今天我来分享关于 ”ConcurrentHashMap 底层实现原理“ 这个问题,

看看普通人和高手是如何回答的!

普通人:

嗯.. ConcurrentHashMap是用数组和链表的方式来实现的,嗯… 在JDK1.8里面还引入了红黑树。然后链表和红黑树是解决hash冲突的。嗯……

高手:

这个问题我从这三个方面来回答:

  1. ConcurrentHashMap的整体架构
  2. ConcurrentHashMap的基本功能
  3. ConcurrentHashMap在性能方面的优化
  • ConcurrentHashMap的整体架构



    这个是ConcurrentHashMap在JDK1.8中的存储结构,它是由数组、单向链表、红黑树组成。

    当我们初始化一个ConcurrentHashMap实例时,默认会初始化一个长度为16的数组。由于ConcurrentHashMap它的核心仍然是hash表,所以必然会存在hash冲突问题。

    ConcurrentHashMap采用链式寻址法来解决hash冲突。

    当hash冲突比较多的时候,会造成链表长度较长,这种情况会使得ConcurrentHashMap中数据元素的查询复杂度变成O(n)。因此在JDK1.8中,引入了红黑树的机制。

    当数组长度大于64并且链表长度大于等于8的时候,单项链表就会转换为红黑树。

    另外,随着ConcurrentHashMap的动态扩容,一旦链表长度小于8,红黑树会退化成单向链表。

  • ConcurrentHashMap的基本功能

    ConcurrentHashMap本质上是一个HashMap,因此功能和HashMap一样,但是ConcurrentHashMap在HashMap的基础上,提供了并发安全的实现。

    并发安全的主要实现是通过对指定的Node节点加锁,来保证数据更新的安全性。

  • ConcurrentHashMap在性能方面做的优化

    如果在并发性能和数据安全性之间做好平衡,在很多地方都有类似的设计,比如cpu的三级缓存、mysql的buffer_pool、Synchronized的锁升级等等。

    ConcurrentHashMap也做了类似的优化,主要体现在以下几个方面:

    • 在JDK1.8中,ConcurrentHashMap锁的粒度是数组中的某一个节点,而在JDK1.7,锁定的是Segment,锁的范围要更大,因此性能上会更低。

    • 引入红黑树,降低了数据查询的时间复杂度,红黑树的时间复杂度是O(logn)。

    • 当数组长度不够时,ConcurrentHashMap需要对数组进行扩容,在扩容的实现上,ConcurrentHashMap引入了多线程并发扩容的机制,简单来说就是多个线程对原始数组进行分片后,每个线程负责一个分片的数据迁移,从而提升了扩容过程中数据迁移的效率。

    • ConcurrentHashMap中有一个size()方法来获取总的元素个数,而在多线程并发场景中,在保证原子性的前提下来实现元素个数的累加,性能是非常低的。ConcurrentHashMap在这个方面的优化主要体现在两个点:

      • 当线程竞争不激烈时,直接采用CAS来实现元素个数的原子递增。
      • 如果线程竞争激烈,使用一个数组来维护元素个数,如果要增加总的元素个数,则直接从数组中随机选择一个,再通过CAS实现原子递增。它的核心思想是引入了数组来实现对并发更新的负载。

以上就是我对这个问题的理解!

总结

从高手的回答中可以看到,ConcurrentHashMap里面有很多设计思想值得学习和借鉴。

比如锁粒度控制、分段锁的设计等,它们都可以应用在实际业务场景中。

很多时候大家会认为这种面试题毫无价值,当你有足够的积累之后,你会发现从这些技术底层的设计思想中能够获得很多设计思路。

本期的普通人VS高手面试系列就到这里结束了,喜欢的朋友记得点赞收藏。

部分高手面试文档已整理,需要的小伙伴可以私信或者评论区留言。

另外,我也陆续收到了很多小伙伴的面试题,我会在后续的内容中逐步更新给到大家!

【面试普通人VS高手系列】ConcurrentHashMap 底层具体实现知道吗?实现原理是什么?的更多相关文章

  1. 【面试普通人VS高手系列】谈谈你对AQS的理解

    AQS是AbstractQueuedSynchronizer的简称,是并发编程中比较核心的组件. 在很多大厂的面试中,面试官对于并发编程的考核要求相对较高,简单来说,如果你不懂并发编程,那么你很难通过 ...

  2. 【面试普通人VS高手系列】HashMap是怎么解决哈希冲突的?

    常用数据结构基本上是面试必问的问题,比如HashMap.LinkList.ConcurrentHashMap等. 关于HashMap,有个学员私信了我一个面试题说: "HashMap是怎么解 ...

  3. 【面试普通人VS高手系列】Spring Boot中自动装配机制的原理

    最近一个粉丝说,他面试了4个公司,有三个公司问他:"Spring Boot 中自动装配机制的原理" 他回答了,感觉没回答错误,但是怎么就没给offer呢? 对于这个问题,看看普通人 ...

  4. 【面试普通人VS高手系列】死锁的发生原因和怎么避免

    一个去阿里面试的小伙伴私信我说:今天被一个死锁的问题难到了. 平常我都特意看了死锁这块的内容,但是回答的时候就想不起来. 这里可能存在一个误区,认为技术是要靠记的. 大家可以想想,平时写代码的时候,这 ...

  5. 【面试普通人VS高手系列】请说一下你对分布式锁的理解,以及分布式锁的实现

    一个工作了7年的Java程序员,私信我关于分布式锁的问题. 一上来就两个灵魂拷问: Redis锁超时怎么办? Redis主从切换导致锁失效怎么办? 我说,别着急,这些都是小问题. 那么,关于" ...

  6. 【面试普通人VS高手系列】volatile关键字有什么用?它的实现原理是什么?

    一个工作了6年的Java程序员,在阿里二面,被问到"volatile"关键字. 然后,就没有然后了- 同样,另外一个去美团面试的工作4年的小伙伴,也被"volatile关 ...

  7. 【面试普通人VS高手系列】说说缓存雪崩和缓存穿透的理解,以及如何避免?

    听说10个人去互联网公司面试,有9个人会被问到缓存雪崩和缓存穿透的问题. 听说,这9个人里面,至少有8个人回答得不完整. 而这8个人里面,全都是在网上找的各种面试资料去应付的,并没有真正理解. 当然, ...

  8. 【面试普通人VS高手系列】说一说Mybatis里面的缓存机制

    一个工作了 5年的程序员,在私信里面不断向我诉苦. 他说,他用了Mybatis这么久,怎么滴也算是精通Mybatis了吧. 结果竟然在Mybatis这个面试题上翻车了! 真的好烦! 好吧,我们今天来看 ...

  9. 【面试普通人VS高手系列】Fail-safe机制与Fail-fast机制分别有什么作用

    前段时间一个小伙伴去面试,遇到这样一个问题. "Fail-safe机制与Fail-fast机制分别有什么作用" 他说他听到这个问题的时候,脑子里满脸问号.那么今天我们来看一下,关于 ...

随机推荐

  1. SINAMICS S120的核心控制单元CU320使用教程,电机模块接线

    SINAMICS是西门子公司新一代的驱动产品,它正在逐步取代现有的MASTERDRIVES及SIMODRIVE系列的驱动系统.SINAMICS S120是集V/f控制.矢量控制和伺服控制于一体的多轴驱 ...

  2. J20航模遥控器开源项目系列教程(七)PPM输出 | 关于按键版本和旋转编码器版本的兼容说明、布局建议 | 关于MINI版PCB的兼容说明

    我们的开源宗旨:自由 协调 开放 合作 共享 拥抱开源,丰富国内开源生态,开展多人运动,欢迎加入我们哈~ 和一群志同道合的人,做自己所热爱的事! 项目开源地址:https://github.com/J ...

  3. [USACO08OPEN]牛的街区Cow Neighborhoods

    题目描述: luogu 题解: 技巧题. 曼哈顿距离:$|x1-x2|+|y1-y2|$ 切比雪夫距离:$\max(|x1-x2|,|y1-y2|)$ 曼哈顿距离转切比雪夫距离:$(x,y)-> ...

  4. z-index原理及适用范围

    z-index原理及适用范围 原理 z-index这个属性控制着元素在z轴上的表现形式,堆叠顺序是当前元素位于z轴上的值,数值越大说明元素的堆叠1顺序越高,越靠近屏幕. 适用范围 <div cl ...

  5. 什么是内部类?Static Nested Class和Inner Class的不同?

    内部类就是在一个类的内部定义的类,内部类中不能定义静态成员,内部类可以直接访问外部类中的成员变量,内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中.在方法外部定义的内部类前面可以加上st ...

  6. 什么是 Executors 框架?

    Executor 框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框 架. 无限制的创建线程会引起应用程序内存溢出.所以创建一个线程池是个更好的的 解决方案,因为可以限制线程的数量并且可以 ...

  7. Redis的数据类型操作(二)

    1.String:key-value(做缓存) Redis中所有的数据都是字符串.命令不区分大小写,key是区分大小写的.Redis是单线程的.Redis中不适合保存内容大的数据. get.set.i ...

  8. Zookeeper 的典型应用场景 ?

    Zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架,开发人员 可以使用它来进行分布式数据的发布和订阅. 通过对 Zookeeper 中丰富的数据节点进行交叉使用,配合 Watch ...

  9. 学习RabbitMQ(五)

    消息中间件就是在消息的传输过程中保存消息的容器.消息中间件再将消息从它的源中继到它的目标时充当中间人的作用.队列的主要目的是提供路由并保证消息的传递:如果发送消息时接收者不可用,消息队列会保留消息,直 ...

  10. Linux下切换python2和python3

    为什么需要有两个版本的Python Python2和Python3不兼容是每个接触过Python的开发者都知道的事,虽说Python3是未来,但是仍然有很多项目采用Python2开发.Linux的许多 ...