ConcurrentHashMap原理简介

本文详细介绍了ConcurrentHashMap的实现原理,包括其锁分段技术、get和put操作流程及扩容机制,并对比分析了ConcurrentLinkedQueue的特点,同时概述了几种常见的阻塞队列及其操作方式。

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

并发容器和框架:

ConcurrentHashMap:

在激烈的并发环境下性能优异的原因在于使用了锁分段技术,ConcurrentHashMap里面维持一个Segment数组,每个Segment就相当于一个HashMap表,每个Segment继承了ReentrantLock。每个Segment维持一个tabel,即一个HashEntry数组,每个HashEntry又是一个链表结构。Segment数组长度和table数组长度都是2^N,这样方便使用散列散列算法定位:都与数组的长度减一再相“与”,但是相“与”的值不一样,定位Segment使用的值是hashcode再散列后的高位,而定位hashEntry直接使用再散列后的值。目的是避免俩次散列后的值一样。

ConcurrentHashMap的get操作先是定位到Segment上,然后调用Segment的get操作,get操作的高效之处在于整个get过程不需要加锁(除非得到的值是空才会加锁重读),为什么不需要加锁读,这是因为统计当前Segment大小的count字段和用于存储值的HashEntry的value都被定义成为了Volatile,这样根据Volatile的语义,总能读取到最新的值。

ConcurrentHashMap的put操作先是定位到Segment上,然后调用Segment的put操作,写操作要加锁,且需要经历俩个步骤:1:在插入数据前判断是否需要对Segment里面的HashEntry数组进行扩容,如果超过阈值,则对数组进行扩容。

2:在扩容的时候,先是创建一个容量是原来俩倍的数组,然后将原数组里面的元素再散列后插入新的数组里面,

ConcurrentHashMap里面的插入操作是在HashEntry链表的头结点插入的,删除操作需要复制之前的所有节点,因为HashEntry里面的next引用是final的。

ConcurrentHashMap的size操作:先尝试2次不锁住Segment的方式统计各个Segment的大小,如果统计过程中容器的大小发生了变化(通过modCount查看,每次put,remove,clean操作都会使modCount变量加1,且modCount变量时Volatile的),则进行加锁统计Segment的大小。

ConcurrentLinkedQueue:

入队列有俩步骤:1:将入队节点设置成当前队列尾节点的下一个节点,2:更新tail节点(tail节点并不总是指向尾节点,这样做是为了减少CAS更新tail节点的次数,提高入队效率),如果tail节点的next节点不为空,则将入队节点设置成tail节点,如果tail节点的next节点为空,则将入队节点设置成tail的next节点。

出队列:首先获取头结点的元素,然后判断头结点元素是否为空,如果为空,表示另外一个线程已经进行了一次出队操作取走该元素,如果不为空,则使用CAS的方式将头节点的引用设为空,如果成功,直接返回头结点的元素,否则,需要重新获取头结点。

ConcurrentLinkedQueue是无阻塞的并发队列。

阻塞的并发队列有如下几种:

ArrayBlockingQueue:

LinkedBlockingQueue:

PriorityBlockingQueue:

DelayQueue

SynchronousQueue

LinkedTransferQueue

LinkedBlockingQueue

他们都有4种处理方式:

1:add(e),remove(),element():抛出异常

2:offer(e),poll(),peek():返回特殊值

3:put(e),take():一直阻塞

4:offer(e,time,unit),poll(time,unit):超时退出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值