=====================
package leetcode0606.JUC.ConcurrentHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class filed {
// 散列表默认值
private static final int DEFAULT_CAPACITY = 16;
// 负载因子
private static final float LOAD_FACTOR = 0.75f;
// 树化阈值,指定桶位链表长度达到8时,有可能会树化
static final int TREEIFY_THRESHOLD = 8;
// 红黑树中的元素<=6,退化为链表
static final int UNTREEIFY_THRESHOLD = 6;
// table数组长度达到64,某一个桶位链表长度达到8时,才会树化
static final int MIN_TREEIFY_CAPACITY = 64;
// 扩容时,每个线程迁移数据的最小步长。控制了线程迁移任务最小区间
private static final int MIN_TRANSFER_STRIDE = 16;
// 扩容时生成的一个 标识戳
private static int RESIZE_STAMP_BITS = 16;
// The maximum number of threads that can help resize
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1; // 65535
// The bit shift for recording size stamp in sizeCtl.
private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
// 当node节点的哈希值=-1时,表示当前节点是FWD节点,已经迁移了。
static final int MOVED = -1; // hash for forwarding nodes
// 当node节点已经树化,当前节点为treeBin对象,此对象代理擦操作红黑树
static final int TREEBIN = -2; // hash for roots of trees
// 1个0 31个1 ,为了将负数变为正数
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
// 系统的CPU数量
static final int NCPU = Runtime.getRuntime().availableProcessors();
/*
成员属性=------------------------
*/
// 散列表 ,长度一定是2的次幂
transient volatile ConcurrentHashMap.Node<K,V>[] table;
// 扩容过程中,会将扩容中的新table赋值给nextTable 保持引用,扩容结束之后,这里会被设置为null
private transient volatile ConcurrentHashMap.Node<K,V>[] nextTable;
//
private transient volatile long baseCount;
// LongAdder cellsBusy = 0 表示LongAdder对象处于无锁状态
private transient volatile int cellsBusy;
// cells数组。 总数 = sum(cells) + basecount
private transient volatile ConcurrentHashMap.CounterCell[] counterCells;
// 难点!!!
/*
sizeCtl
<0 -1 表示table正在初始化(有线程在创建table数组),当前线程需要自旋等待
表示当前map正在扩容,高16位表示 扩容的标识戳。。。。低16位表示 (1+nThread)即当前参数并发扩容的线程数量
=0 表示创建table数组时使用 默认大小(16)
>0 如果table数组未初始化,表示初始化大小。
如果table数组已经初始化,表示下次扩容时的 触发条件(阈值)
*/
private transient volatile int sizeCtl;
// 扩容过程中,记录当前进度,所有线程都需要从transferIndex中分配区间任务,去执行自己的任务
private transient volatile int transferIndex;
// Unsafe类的引用
private static final sun.misc.Unsafe U;
// sizeCtl在内存中的偏移地址,地址=ConH 的内存地址 + 偏移地址、、、、、、、、、、
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
// 表示数组第一个元素的偏移地址
private static final long ABASE;
private static final int ASHIFT;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = ConcurrentHashMap.class;
SIZECTL = U.objectFieldOffset
(k.getDeclaredField("sizeCtl"));
TRANSFERINDEX = U.objectFieldOffset
(k.getDeclaredField("transferIndex"));
BASECOUNT = U.objectFieldOffset
(k.getDeclaredField("baseCount"));
CELLSBUSY = U.objectFieldOffset
(k.getDeclaredField("cellsBusy"));
Class<?> ck = ConcurrentHashMap.CounterCell.class;
CELLVALUE = U.objectFieldOffset
(ck.getDeclaredField("value"));
Class<?> ak = ConcurrentHashMap.Node[].class;
ABASE = U.arrayBaseOffset(ak);
// 表示数组单元所占用空间大小,scale表示Node[]数组中每一个单元所占空间的大小
int scale = U.arrayIndexScale(ak);
// 假如 scale = 16 = 10000 那么sclae-1 = 1111 &之后得到0000
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
// numberOfLeadingZeros(scale) 方法当前数值转换为二进制后,从高位到低位开始统计有多少个连续的0
// numberOfLeadingZeros(10000) = (32-5) = 27 ; ASHIT = 4
// ASHIFT即scale的二进制表示。 当对某个单元格进行寻址时:地址=ABASE + (第几个 * scale)
// 但是设计者觉的太low了,因此改为了 地址=ABASE + (n << ASHIFT)
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (Exception e) {
throw new Error(e);
}
}
static class Node<K,V> implements Map.Entry<K,V> {
// hash ,key Node一经创建就无法修改了。是final修饰的
final int hash;
final K key;
// value值是可以被修改的。
volatile V val;
volatile ConcurrentHashMap.Node<K,V> next;
Node(int hash, K key, V val, ConcurrentHashMap.Node<K,V> next) {
}
this.hash = hash;
this.key = key;
this.val = val;
this.next = next;
}
}