java-concurrentHashMap

put方法执行逻辑

1. 初始化方法initTable 这个方法在自旋

  在第一次put的时候table尚未初始化,会调用初始化table的方法,初始化方法支持并发,但是只会有一个线程去执行table数组的初始化,创建的线程会把sizeCtl属性设置为-1代表正在初始化,其他线程检查sizeCtl属性是发现是-1就让出cpu执行权, 也就是创建一个node[] 赋值给map的table属性

2. 执行完初始化table方法之后会自旋,继续put值 这时会根据key定位到table对应的桶位,如果桶位为null 就使用cas放入node 如果cas放入成功退出自旋 如果失败说明冲突了 继续自旋

3. 判断是否是在扩容 如果在扩容中 当前put线程帮助扩容 否则进行进行下次自旋

4. 根据线程hash定位到的桶位拿到桶位头结点,以这个对象为锁,如果桶位是链表就对比并替换,如果是红黑树就替换或插入

5. 然后判断是否需要扩容table,如果到达了扩容阈值就扩容

6.扩容时如果是第一个进来扩容是线程会创建一个新的表长度是旧table的1倍 然后线程进入一个自旋

7. 如果迁移已经完成就执行退出逻辑,如果未完成查看桶位是否已经分配完 分配完直接退出 未分配完分配新的迁移区间

8. 然后线程执行迁移逻辑如果迁移完再去获取新的迁移区间等所有的迁移完才能退出

9. 如果迁移的桶位是null直接赋值fwd代表已经迁移完成,如果桶位不为null就使用当前桶位的头结点作为锁,迁移的桶位是链表就,把旧链表分高低链表,分别放入fwd节点持有的newTable的原始 桶位和原始桶位+扩容值的桶位

10. 如果迁移的桶位是红黑树,因为concurrentHashmap持有的treenode持有红黑树和双向链表两个数据结构,迁移的时候使用的双向链表,把双向链表拆分成高低链,拆完如果链表小于等于6就把treenode转为普通的node,如果大于6就还封装为红黑树,存储新的桶位 线程进入下个桶位处理迁移

这里有的细节是:如果红黑树只分出一个链来,并且链的长度大于6,说明这个旧的红黑树全是低位链或者全是高位链,就把这个红黑树直接付给新的桶位即可

get方法执行逻辑

根据key的hash定位到table的桶位,对比一样就返回val,不一样的话如果是链表就遍历对比,如果桶位存储的是fwd节点或者红黑树节点,就进入fwd去查询,fwd中存储的也是table逻辑跟外层一样先找到key转为hash值后求出对应桶位,如果是链表就遍历对比,如果是fwd就再进入 如果是红黑树就再红黑树里找 不存再就返回null

remove方法执行逻辑

没什么可说的,调用的concurrentHashMap 的 replaceNode 方法,先根据key定位到slot,如果正在扩容就帮助扩容,如果slot上的是链表就遍历比对赋值null,如果是红黑树,就搜索红黑树然后删除

原文地址:https://www.cnblogs.com/isnotnull/p/14466253.html