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

《彻底理解HashMap及LinkedHashMap》介绍了HashMap及LinkedHashMap的数据结构和原理,不过遗憾的是,HashMap不是线程安全的。也就是说,在多线程环境下,操作HashMap会导致各种各样的线程安全问题,比如在HashMap扩容重哈希时出现的死循环问题,脏读问题等。庆幸的是,JDK为我们解决了这个问题,它为HashMap提供了一个线程安全高效的版本ConcurrentHashMap。
在jdk1.8中,实现了完全抛弃Segment分段锁的机制,利用了CAS+Synchronized来保证并发更新的安全,底层依然采用数组+链表+红黑树的存储结构。
接下来慢慢深入的了解和探讨这个线程安全下的高效map
一:基础入门的一些基本常量/变量及其含义
1)散列表数组最大限制

private static final int MAXIMUM_CAPACITY = 1 << 30;

2)散列表默认值

 private static final int DEFAULT_CAPACITY = 16;

3)负载因子

 private static final float LOAD_FACTOR = 0.75f;

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

static final int TREEIFY_THRESHOLD = 8;

5)树转为链表阈值

 static final int UNTREEIFY_THRESHOLD = 6;

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

    static final int MIN_TREEIFY_CAPACITY = 64;

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

   private static final int MIN_TRANSFER_STRIDE = 16;

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

 private static int RESIZE_STAMP_BITS = 16;
  1. node节点的hash值为 -1时,表示当前节点是FWD节点
static final int MOVED     = -1;

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

static final int TREEBIN   = -2;

11)当前系统CPU的数量

static final int NCPU = Runtime.getRuntime().availableProcessors();

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

  transient volatile Node<K,V>[] table;

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

private transient volatile Node<K,V>[] nextTable;

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

  private transient volatile long 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已经初始化了,表示下次扩容时的出发条件(阈值)

 private transient volatile int sizeCtl;

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

 private transient volatile int transferIndex;

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

private transient volatile int cellsBusy;

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

    private transient volatile CounterCell[] counterCells;

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

Guess you like

Origin blog.csdn.net/qq_35529931/article/details/119721407