ConcurrentHashMap源码学习心得帮助快速面试

前言

ConcurrentHashMap作为一个集合类,其实就是一种数据结构。类似这种源码学习我总结,分为三大块。第一就是整体思路,对于目标源码的理解。是什么,为什么,干什么,怎么用 组合拳打一通。第二就是精髓地方(包括对比同类型数据结构),也就是哪些地方设计得好,为什么好,什么时候可以借鉴、借鉴什么。另:面试的时候要说出这些方法名称显得专业,这个要背一下应该也不难。第三不同于其他jar包,作为一个数据存储结构,也要从重要的基础方法上研究,比如存数据、取数据、删数据、扩容等。

1、整体思路 

是什么:集合框架中的一种并发哈希表,它允许多个线程同时访问数据而不需要进行外部同步。

底层和hashmap的数据结构设计类似,也是由数组加链表以及红黑树构成。

锁的粒度:hashtable所有方法都对整个map加锁。ConcurrentHashMap 1.7是对segment加锁,1.8是对桶加锁。

2、重要方法列举

putVal()方法,put方法实际调用putVal()。putVal()方法可以通过传入参数决定是否覆盖原来的值。初始化数组是在这个阶段完成,并不是new的时候完成的。

transfer()方法,并发扩容。扩容实际是在分发任务,所有参与扩容的线程,在做一个循环领取任务的动作(任务的拆分规则基于当前数据量,以及cpu的线程数)。

3、精妙设计点

3.1 长度定义为2的n次方好处有:

        3.1.1基于这个设计,长度减一操作就可以得到二进制位都是1的数,这样使用这个数对数据key的hash值进行&运算的时候,就能够根据hash值不同位的数据的不同把他均匀地放到各个桶(数组的位置称为桶)。

        3.1.2基于这个设计,扩容的时候,(因为是对数据key的hash值进行&运算决定存在哪个桶)新数据存放的索引位置要么是原数据存放的索引位置,要么是索引位置加上2的n-1次方。这样对于数据迁移产生便利性。

        3.1.3基于这个设计,在数据量巨大的情况,也可以使得扩容次数变得有限(logn)。且可以直接定义较大的初始值,扩容次数将非常少。

3.2 扩容时候的lastRun机制

3.2.1 lastRun机制,因为扩容位置只可能在原索引以及原索引位置加上2的n-1次方,这两种情况。扩容的时候,一次遍历先找到最早的后续节点一致的位置,第二次遍历到这个位置的时候,直接把整个链表摘过去。减少了后续构建新节点的过程。

3.3 取数据putVal()时,如果当前状态处于扩容状态。取数据的线程会参与扩容(helpTransfer()),而不是等待扩容完毕。

3.4 管理数组位置的头结点的hash值,来代表状态,-1代表正在扩容。。这样可以让putVal的时候,仅在此处任务被分发出去扩容的时候,才会等待(其实是参与扩容,对于当前线程的调用方而言是在等待),大大减少了putval等待的概率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值