天天看点

jdk1.8中对ConcurrentHashMap的理解(一)

《彻底理解HashMap及LinkedHashMap》介绍了HashMap及LinkedHashMap的数据结构和原理,不过遗憾的是,HashMap不是线程安全的。也就是说,在多线程环境下,操作HashMap会导致各种各样的线程安全问题,比如在HashMap扩容重哈希时出现的死循环问题,脏读问题等。庆幸的是,JDK为我们解决了这个问题,它为HashMap提供了一个线程安全高效的版本ConcurrentHashMap。

在jdk1.8中,实现了完全抛弃Segment分段锁的机制,利用了CAS+Synchronized来保证并发更新的安全,底层依然采用数组+链表+红黑树的存储结构。

接下来慢慢深入的了解和探讨这个线程安全下的高效map

一:基础入门的一些基本常量/变量及其含义

1)散列表数组最大限制

2)散列表默认值

3)负载因子

4)树化阈值,指定桶位,链表长度达到8的话,可能发生树化操作

5)树转为链表阈值

6)只有当table数组长度达到64,且某个桶位的链表长度达到8,才会整整的树化

7)线程迁移数据最小步长,控制线程迁移任务最小区间的一个值

8)扩容相关,计算扩容时生成的一个标识戳

  1. node节点的hash值为 -1时,表示当前节点是FWD节点

10)node节点的hash值为 -2时,表示当前节点已经树化,且当前节点为TreeBin对象,TreeBin对象代理操作红黑树

11)当前系统CPU的数量

12)散列表,长度一定是2的次方数

13)扩容过程中,会将扩容中新的table,赋值给nextTable,保持引用,扩容之后,这里会被设置为null

14)baseCount 未发生竞争或者 当前LongAddr处于枷锁状态时,增量累计到 baseCount中

15)

sizeCtl <0

1. -1表示当前table正在初始化(有线程在创建table数组),当前线程需要自旋等待

2.非-1时.示当前map正在进行扩容,高16位表示:扩容表示戳; 低16位表示:(1+nThread)当前参与并发扩容的线程数量 sizeCtrl = 0

1.表示创建table数组时,使用DEFAULT_CAPACITY为的大小

sizeCtrl > 0时

1.如果table未初始化,表示初始化大小

2.如果table已经初始化了,表示下次扩容时的出发条件(阈值)

16)记录扩容过程中,当前的进度,所有的线程都需要从transferIndex中的任务

17)cellsBusy 0表示当前LongAddr对象无锁状态,1表示加锁状态

18)当baseCount发生竞争后,会创建cells数组。线程会通过计算hash值 取到自己的cell,将增量累计到指定的cell中

以上为jdk1.8中源码解读中可能需要用到的常量和变量的含义。下一节,探讨下该map中的put操作涉及到的相关步骤。