ConcurrentHashMap JDK1.8 源码分析
1 助记
JDK 1.7 使用的是 segment 分段锁,默认为 16 个 segment,扩容分别在各自的 segment 进行。
JDK 1.8 使用的是 Synchronized+CAS 自旋,相应的内部结构和 hashmap 一样,改为了红黑树当 Node 数组为空,直接用 CAS 初始化或者插入数据当 Node 数组节点不为空,需要使用 Sync,因为有很多逻辑判断,例如:链表转红黑树。
2 ConcurrentHashMap 1.8
存储结构
可以发现 Java8 的 ConcurrentHashMap 相对于 Java7 来说变化比较大,不再是之前的 Segment 数组 + HashEntry 数组 + 链表,而是 Node 数组 + 链表 / 红黑树。当冲突链表达到一定长度时,链表会转换成红黑树。
初始化 initTable
ConcurrentHashMap 的初始化是通过自旋和 CAS 操作完成的。里面需要注意的是变量 sizeCtl ,它的值决定着当前的初始化状态。
复制代码
3. put
复制代码
根据 key 计算出 hashcode 。
判断是否需要进行初始化。
即为当前 key 定位出的 Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入,失败则自旋保证成功。
如果当前位置的
hashcode == MOVED == -1
,则需要进行扩容。如果都不满足,则利用 synchronized 锁写入数据。
如果数量大于
TREEIFY_THRESHOLD
则要转换为红黑树。
4. get
复制代码
总结一下 get 过程:
根据 hash 值计算位置。
查找到指定位置,如果头节点就是要找的,直接返回它的 value.
如果头节点 hash 值小于 0 ,说明正在扩容或者是红黑树,查找之。
如果是链表,遍历查找之。
评论