CurrentHashmap知识详解

为什么要使用CurrentHashmap

在多线程中,hashmap的put方法可能会造成死循环的问题,put的时候引发扩容。hashtable虽然是线程安全的,但是在多线程中使用的是synchronized,当一个线程抢到锁之后,别的线程会等待使用锁的线程释放后才会执行,相当于单线程,效率不高,而CurrentHashmap是采用的是分段锁的思想,可以支持16个线程同时执行,效果显然是比较快的。

CurrentHashmap详解

CurrentHashmap1.7
ConcurrentHashMap1.7由Segment数组结构和HashEntry数组组成。Segment是一种可重入锁,是一种数组和链表的结构,一个Segment中包含一个HashEntry数组,每个HashEntry又是一个链表结构。HashEntry只是初始化第一个位置的HashEntry,默认初始容量是2。后序的直接拷贝使用。
ConcurrentHashMap1.7的put过程
在这里插入图片描述
如果put的值为null,直接抛出异常,否则记算hash,然后计算J在哪个Segments对象,hash值右移28位,然后和15进行与运算。如果通过unsafe类获取到的为null,则创建对象。然后执行put操作。
在这里插入图片描述
右上图可看到,创建对象的时厚,进行了多次判断,第一次判断获取基本参数,初始容量,加载因子等,第二次判断创建hashentry,第三次判断后在修改segment。752行使用cas操作就是为了保证线程的安全性。
在执行put方法的时候,会判断是否持有lock锁,如果持有该锁,然后在第二次计算在hashentry的位置。如果没有持有该锁,会进入到433行的方法,短暂自旋(最大64次)最后会判断冲突位置的链表的头结点是否发生变化,发生变化会重新获取当前链表的结构,然后插入。
在这里插入图片描述

CurrentHashmap1.8
ConcurrentHashMap1.8采用Node类作为基本的存储单元,每个键值对(key-value)都存储在一个Node中,去除了Segment分段锁的数据结构,主要是基于CAS操作保证保证数据的获取以及使synchronized关键字对相应数据段加锁实现了主要功能,这进一步提高了并发性。
在这里插入图片描述
1013行的bidcount的作用是当bincount大于8的时候,转化为红黑树。1018行确认下标位置后,使用cas操作,确保只能创建一个node对象,修改成功后退出。
在这里插入图片描述
其中sizeCtl默认值为0,-1表示有一个线程在扩容或者初始化,-2表示有两个在扩容,所以当前线程会释放cpu执行权。
在这里插入图片描述
在刚刚1018行的时候已经说过,在当前node节点没有冲突的时候,会使用cas操作只能创建一个对象,如果node节点已经存在,则使用synchronized锁住当前对象。1034行就是key值相等的话进行修改操作,否则执行1043行,执行put操作。

CurrentHashmap1.7和1.8的区别

1.7使用数组+链表+cas 分段锁 +lock锁+unsafe类
1.8使用node节点数组+链表+红黑树 index冲突使用synchronized,没有使用cas

CurrentHashmap知识详解就总结这么多,如果错误谢谢各位大佬留言,谢谢大家!!!

猜你喜欢

转载自blog.csdn.net/baidu_39170202/article/details/121307288