七日打卡:ConcurrentHashMap理解
- 数据结构 ConcurrentHashMap的数据结构与HashMap基本类似,区别在于:1、内部在数据 写入时加了同步机制(分段锁)保证线程安全,读操作是无锁操作;2、扩容时老数据的转移 是并发执行的,这样扩容的效率更高。
- 并发安全控制 Java7 ConcurrentHashMap基于ReentrantLock实现分段锁

- Java8中 ConcurrentHashMap基于分段锁+CAS保证线程安全,分段锁基于synchronized 关键字实现。

- 重要成员变量
- ConcurrentHashMap拥有出色的性能, 在真正掌握内部结构时, 先要掌握比较重要的成员:
- LOAD_FACTOR: 负载因子, 默认75%, 当table使用率达到75%时, 为减少table 的hash碰撞, tabel长度将扩容一倍。负载因子计算: 元素总个数%table.lengh - TREEIFY_THRESHOLD: 默认8, 当链表长度达到8时, 将结构转变为红黑树。
- UNTREEIFY_THRESHOLD: 默认6, 红黑树转变为链表的阈值。 - MIN_TRANSFER_STRIDE: 默认16, table扩容时, 每个线程最少迁移table的槽位 个数。
- MOVED: 值为-1, 当Node.hash为MOVED时, 代表着table正在扩容 TREEBIN, 置为-2, 代表此元素后接红黑树。
- nextTable: table迁移过程临时变量, 在迁移过程中将元素全部迁移到nextTable 上。
- sizeCtl: 用来标志table初始化和扩容的,不同的取值代表着不同的含义:
- 0: table还没有被初始化
- -1: table正在初始化
- 小于-1: 实际值为resizeStamp(n) <<RESIZE_STAMP_SHIFT+2, 表明table正在扩容
- 大于0: 初始化完成后, 代表table最大存放元素 的个数, 默认为0.75*n
- transferIndex: table容量从n扩到2n时, 是从索引n->1的元素开始迁移, transferIndex代表当前已经迁移的元素下标
- ForwardingNode: 一个特殊的Node节点, 其hashcode=MOVED, 代表着此时 table正在做扩容操作。扩容期间, 若table某个元素为null, 那么该元素设置为 ForwardingNode, 当下个线程向这个元素插入数据时, 检查hashcode=MOVED, 就会帮着扩容。
- ConcurrentHashMap由三部分构成, table+链表+红黑树, 其中table是一个数组, 既然是 数组, 必须要在使用时确定数组的大小, 当table存放的元素过多时, 就需要扩容, 以减少碰撞 发生次数, 本文就讲解扩容的过程。扩容检查主要发生在插入元素(putVal())的过程: 一个线程插完元素后, 检查table使用率, 若超过阈值, 调用transfer进行扩容一个线程插入数据时, 发现table对应元素的hash=MOVED, 那么调用 helpTransfer()协助扩容。