数据结构:HashMap、ConcurrentHashMap底层原理

HashMap底层原理

 

JDK1.7

put方法

存的是键值对对象

第一步:初始化一个数组(第一次需要初始化,后面不需要)

第一次放元素的时候还没有开辟空间,默认值为16(这个值一定是2的幂次方)

第二步:判断,如果key==null,走putForNullkey方法

 

在talbe[0]链表中查找key为null的元素,如果找到,则将value重新赋值给这个元素的value,并返回原来的value。如果没找到,则将这个元素添加到talbe[0]链表的表头。 

第三步:根据key的值计算一个哈希值

h右移动再异或的原因:让高位参与运算,防止计算出的数组下标相同的太多(扰动函数)

 

 第四步:根据哈希值和数组容量计算数组下标

与运算,算出一个数组下标(与运算比取余要快)

与运算的过程:二进制运算,都为1才为1,否则为0

这就是为什么数组容量一定要是2的幂次方,这样才能保证计算出的数组下标是合法的

计算结果与高位无关,等于传入的hash的最后四位(所以要在上一步计算hash的时候,对hashCode进行位移和异或让高位参与运算)

第五步:遍历当前数组下标的链表,判断是否已经存在相同的key

如果存在,就把当前元素的值覆盖,并返回之前的值

哈希值相等不一定key相同,但哈希值不等key一定不相同

第六步:添加元素(头插法)

​​​​​​​

1 扩容

1.1判断是否需要扩容

条件一:size大于扩容的阈值,threshold默认为12(16*0.75)

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 初始容量

static final float DEFAULT_LOAD_FACTOR = 0.75f;//加载因子=填入哈希表中的数据个数/哈希表的长度

条件二:当前的要放入的位置是空的

1.2扩容的方法

创建一个新的数组,长度是原来的两倍

1.2.1 转移元素

如果扩容前:数组容量为16,元素的数组下标为5

那么扩容后:数组容量为32,元素的数组下标为5+16=21或者还是5

扩容转移元素后,链表的顺序会倒过来,出现线程安全问题!

 

1.2.2重哈希

第一步:判断是否需要重哈希 

 这个值可以自己配,如果没有配,就是默认值。一般不用配

2.添加:头插法+向下移动

用e保留现在的头节点

把创建新节点的Entry对象,并放到数组中作为头节点,e作为新节点Entry对象的next域的参数传递

get方法 

JDK1.8

put方法


链表长度大于8并且数组长度大于64时,才会转换为红黑树。如果链表长度大于8,但是数组长度小于64时,还是会进行扩容操作,不会转换为红黑树。在红黑树的元素小于6的时候会变成链表。

链表转红黑树的原因:TreeNodes的大小大约是普通节点的两倍,最开始使用链表的时候,空间占用是比较少的,而且由于链表短,所以查询时间也没有太大的问题。可是当链表越来越长,需要用红黑树的形式来保证查询的效率。

阈值为8的原因:通常如果 hash 算法正常的话,那么链表的长度也不会很长,那么红黑树也不会带来明显的查询时间上的优势,反而会增加空间负担。所以通常情况下,并没有必要转为红黑树,所以就选择了概率非常小,小于千万分之一概率,也就是长度为 8 的概率,把长度 8 作为转化的默认阈值。

第一步:初始化一个数组(第一次需要初始化,后面不需要)

第二步:插入节点(尾插法

判断该元素的数组下标处是用的红黑树还是链表:

如果是树,遍历红黑树,并加入元素

如果是链表,遍历链表,并用尾插法加入元素(计算链表的长度,判断是否有相同的键)

第三步:扩容

1.7中ConcurrentHashMap底层原理

HashMap线程不安全的原因:

后执行的key和value会把先执行的key和value覆盖

头插法也会出现线程不安全

 HashTable线程安全的原理:

把这个entry对象本身作为锁,在操作之前先获取锁,操作完之后再释放锁

效率不高的原因:两个线程的index可能不同,但却要等

分段锁,以Segment对象为锁

 

 

初始化后,并发度不会改变了,即Segment数组不会扩容

每个Segment下面的Entry数组的容量相同

扩容的时候是扩容的Entry数组

 1.8中ConcurrentHashMap底层原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值