JDK8中ConcurrentHashMap源码解析

线程安全:使用CAS + synchronized

1.8中没有了Segment[]对象

修改 i的属性:

主内存中的值 = 预期值person.i,那么cpu就可以修改成功,修改为 person.i+1;

若当主内存中的值 != person.i时,那么就不会进行修改,会返回false。

一般会结合自旋的方式来使用cas。

while(true) { }

boolean b = UNSAFE.compareAndSwapInt(person, I_OFFSET, person.i, person.i+1); 

 

1. put()

1.8中 ,concurrentHashMap只有一个Node[]数组:

putVal():

首先计算hash值,然后根据这个 hash & (n - 1),算出下标 i

Unsafe():通过Unsafa()方法从数组中获取第i个元素的值。

CAS自旋new Node<K,V>(),通过cas的操作,将新的Node结点放到数组的第i个位置。如果cas成功,则 break。

若CAS失败,很有可能是由于其它的线程将第i个位置的元素赋值成功了;导致该线程在进行casTabAt()方法判断时,参数不为null,失败返回false。

1.1 ConcurrentHashMap的put方法

在put方法中调用了putVal方法,也是使用头插法

1.7中使用分段锁Segment,1.8中使用 synchronized(f)

当多个线程都准备插入元素,对f --> taable[i] 进行加锁,f对象表示Node[]数组中 一个结点(链表的头结点)。

加锁之后,需要重新检查 f结点 是否还是链表头结点

f结点是链表的结点,则插入链表中:

binCount:记录链表中元素个数

在遍历链表过程中,找到key相等的,则退出循环,返回oldValue。

若key都不相等,则遍历到链表尾,尾插法。然后判断结点个数是否大于阈值,是否树化。

若 结点f 是 TreeBin类型,则为树的一个结点;

TreeBin对象代表一棵红黑树,TreeBin红黑树内部的根节点在插入过程中发生变化,不影响Node[]数组

Tree里面有TreeNode对象:

treeifyBin(Node<K,V>[] tab, int index):树化

tab数组中index 下的链表进行树化,方法中加锁 synchronized

双向链表,hd表示双向链表的头结点

初始化 initTable()

Thread.yield():当前线程放弃cpu,进行下一次cpu资源的争夺

 

1.8 concurrentHashMap扩容

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值