【专栏集合】ConcurrentHashMap

1.8 之前:

使用Segment(分段锁,它继承了ReentrantLock ReentrantLock 是AQS(抽象队列同步框架) 的独占锁模式)在这里插入图片描述
ReentrantLock实现模式
在这里插入图片描述
一个数组分为多个段落,然后每个段落对应一个资源state(int类型 初始为0加锁 +1 释放锁-1 等于0则代表没有被占用),线程并发的时候每个线程会封装成一个node节点进入aqs阻塞队列 队列首节点判断state是否为0 ,为0则+1执行难此资源,如果是独占模式则是等首节点执行完后唤醒后续节点进行获取资源操作;

共享模式如下:不是首节点的会判断自己node.pre是否为首节点如果是则casAndSwap 资源 如果node.pre不是首节点则自旋;

缺点:

1、分段后加锁不连续会导致碎片化,内存资源浪费
2、对象创建后分段数量不变,当进行扩容时,每段大小增加导致锁的粒度增大导致并发能力减弱
3、使用ReentrantLock则需要节点继承AQS来获得同步支持,增加内存开销

1.8 之后:

使用synchronized+cas那么synchronized和cas分别用在了什么地方呢?
synchronized用在锁住数组桶内链表头节点上
cas用在初始化桶中第一个元素的时候会进行cas


数据结构

1.8 之前:

数组+链表

1.8 之后:

数组+链表+红黑树
当数组长度大于60的时候链表长度大于8的时候会变为红黑树


扩容

1.8 之前:

数组默认16 ;当存入数据大小大于16*负载因子(0.75)=12的时候会进行扩容,扩容俩倍,之所以是2倍是因为可以让hashcode更均匀分散

1.8 之后:

数组默认16 ;当存入数据大小大于16*负载因子(0.75)=12的时候会进行扩容,扩容俩倍,之所以是2倍是因为可以让hashcode更均匀分散


链表插入方式

1.8 之前:头插法

并发情况会导致环形链表:
线程一:读取到当前的hashmap情况,在准备扩容时,线程二介入
在这里插入图片描述
线程二:读取hashmap,进行扩容
在这里插入图片描述
线程一:继续执行
在这里插入图片描述
简单来说就是头插法情况下 a>b数组在 1线程进行扩容还没有开始此时cpu调度到了 2线程 然后取值到新数组变成了a先到后b到然后因为头插法 将b插入到了a前面 此时变为b>a 然后 cpu继续调度 1线程 发现b>a 然后自己内存的事a>b 然后就变成了b>a>b

jdk 1.8之后

使用尾插法不会出现环形链表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抵制平庸 拥抱变化

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值