8) 2021-11-21 学习记录,以面试回答口吻记录,拒绝八股 ConcurrentHashMap

简述使用:
使用Java8的版本,Java8以前基于分段锁的形式来实现每一个segment对应n个HashEntry。volatile修饰了HashEntry和下一个元素next,保证了多线程环境下的可见性。锁的对象是segment
Java8开始基于Node数组 加 链表 加 红黑树,锁的对象是node节点,链表的根节点 ,基于CAS和Synchronized实现

原理:

① put方法添加元素,根据key计算hash值,判断是否需要初始化,先拿到node节点,如果首节点为null,通过cas尝试添加,如果f.hash = moved = -1.说明其他线程正在扩容,一起扩容,如果不是,这个时候synchronized锁住f,判断是链表还是红黑树遍历插入,链表长度到8,要么扩容要么转红黑树
解决Hash冲突的问题,链式寻址法,寻找下一个节点为空在存储值
②get方法,根据key计算hash值判断数组是否为null,如果是首节点直接返回,如果是红黑树,查找O(log(n)),如果是链表,循环遍历,get不需要加锁,node的value和next节点都是用volatile修饰的,多线程下修改是可见的。

1 扩容

当值到 0.75*16 = 12 时第一次扩容,一般扩容都两倍先32,64
涉及到数据的迁移,多线程并发协助数据的迁移,高低位迁移,需要迁移的数据放在高位链,不需要迁移的数据放在地位链,再通过n(长度) * hash来计算节点的下标位置,一次性把高位链和地位链set到新的数组的下标的节点

2 元素的统计

数组的方式,分片的思想,比如一个长度32的数组,第一次处理的是 16-31,第二次处理的是0-15,处理完的可以协助别的线程处理数据。
汇总数组+baseCount的值完成数据的累加
当链表的长度大于等于八,并且数组的长度大于64的时候,链表会转换程红黑树

3.并发度

Java7是 分段锁的个数一般是16
Java8是容量大小乘以二的最小的2的倍数

猜你喜欢

转载自blog.csdn.net/qq_45095838/article/details/121462183