面试系列Java中级:谈谈ConcurrentHashMap的原理

本文详细介绍了JDK1.7与1.8中ConcurrentHashMap的不同实现方式。JDK1.7采用Segment+HashEntry分段锁机制,支持16个线程并发读写。而JDK1.8则采用了CAS+Synchronized+Node+红黑树的方式,提高了并发性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JDK1.7 ConcurrentHashMap主要是Segment+HashEntry分段锁实现的

结构上,ConcurrentHashMap1.7 里面包含一个Segment数组,Segment继承了ReentrantLock,Segment则包含HashEntry的数组,HashEntry本身是一个链表结构,具有保存key,value的能力并能指向下一个节点的指针。

实际上,相当于每个Segment都是一个HashMap,默认它的长度是16。也就是支持16个线程的并发读写,Segment之间互不受影响。

Put 流程

其实整个流程类似HashMap,只不过是先定位到具体的Segment,然后通过ReentrantLock去操作
1. 计算hash,定位到segment,segment如果是空就先初始化
2. 使用ReentrantLock加锁,如果获取锁失败则尝试自旋,自旋超过次数就阻塞获取,保证一定获取锁成功
3. 遍历HashEntry,就是和HashMap一样,数组中key和hash一样就直接替换,不存在就再插入链表,链表同样

Get流程 

key通过hash定位到segment,再遍历链表定位到具体的元素上,需要注意的是value是volatile的,所以get是不需要加锁的。

JDK1.8  ConcurrentHashMap主要是CAS+synchronized+Node+红黑树实现的

结构上, ConcurrentHashMap 1.8 抛弃了Segment分段锁机制,采用Node + CAS + Synchronized来保证并发安全进行实现,采用数组+链表+红黑树的存储结构。以数组元素作为锁,利用CAS+Synchronized来保证并发更新的安全,从而实现了对每个数组元素(Node)进行加锁,进一步减少并发冲突的概率。

Put流程 

1. 首先先计算hash,遍历node数组,如果node是空的话,就通过CAS+自旋的方式初始化
2. 如果当前数组位置是空则直接通过CAS自旋写入数据
3. 如果hash==MOVED,说明需要扩容,执行扩容
4. 如果都不满足,就使用synchronized写入数据,写入数据同样判断链表、红黑树,链表写入和HashMap的方式一样,key hash一样就覆盖,反之就尾插法,链表长度超过8就转换成红黑树 

Get流程 

通过key计算hash,如果key hash相同就返回,如果是红黑树按照红黑树获取,都不是就遍历链表获取。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值