HashMap在单线程中非常好用,也不会出现什么问题。但是在多线程中,HashTable的效率太低。后面提供了ConcurrentHashMap解决多线程的问题,后续都以1.8的为对象进行研究。
在1.8中,ConcurrentHashMap的设计与HashMap保持一致,使用了链表和红黑树的组合,当一个链表上的节点数超过8,且总个数超过64,就会触发转为红黑树。
一:开始先了解ConcurrentHashMap中的基础属性
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.树化阈值
static final int TREEIFY_THRESHOLD = 8;
5.联合 TREEIFY_THRESHOLD控制桶位是否树化,只有当table数组长度达到64.且某个桶位的链表长度达到8,才会真正的树化
static final int MIN_TREEIFY_CAPACITY = 64;
6.扩容相关,计算扩容时生成一个 表示戳
private static int RESIZE_STAMP_BITS = 16;
- 65535 表示 并发扩容最多线程数
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
8.扩容相关
private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
9.当node节点的hash值 为-1时,表示当前节点为FWD节点
static final int MOVED = -1;
10.当node节点的hash值 为-2时, 表示当前节点已经树化,且当前节点为TreeBin对象,TreeBin对象代理操作红黑树
static final int TREEBIN = -2;
11.可以将一个负数通过位与运算后得到正数,但是不是取绝对值
static final int HASH_BITS = 0x7fffffff;
12.系统CPU的数量
static final int NCPU = Runtime.getRuntime().availableProcessors();
13.散列表,长度一定是2次方数
transient volatile Node<K,V>[] table;
14.扩容过程中,会将扩容中的新table 赋值给nextTable 保持引用,扩容结束之后,这里会被设置为null
private transient volatile Node<K,V>[] nextTable;
15.未发生竞争时,或者当前LongAdder 处于加锁状态时,增量累加到baseCount
private transient volatile long baseCount;
/**
* sizeCtl < 0
* 1. -1 表示当前table正在初始化(有线程在创建table数组),当前线程需要自旋等待
* 2.表达当前map正在进行扩容 高16位表示:扩容的标识戳 低16位: 表示 1+N Thread 当前参与并发扩容的线程数量
*
* sizeCtl = 0;
* 表示创建map时,使用DEFALUT_CAPACITY 为大小
*
* sizeCtl > 0;
* 1.如果table未初始化,表示初始化大小;
* 2.如果table已经初始化了,表示下次扩容时触发条件(阈值)
*
*/
private transient volatile int sizeCtl;
17.扩容过程中,记录当前进度。所有线程都需要从transferIndex中分配区间任务,去执行自己的任务
private transient volatile int transferIndex;
18.LongAdder中的 cellsBuzy 0表示当前LongAdder对象无锁状态,1表示当前LongAdder对象加锁状态
private transient volatile int cellsBusy;
19.LongAdder 中的cells数组,当baseCount发生竞争后,会创建cells数组.线程会通过计算hash值 取到 自己的cell,将增量累加到指定cell中
private transient volatile CounterCell[] counterCells;
20.表示sizeCtl属性在concurrentHashMap中内存便宜地址
private static final long SIZECTL;
21.表示transferIndex属性在concurrentHashMap中内存便宜地址
private static final long TRANSFERINDEX;
22.表示baseCount属性在concurrentHashMap中内存便宜地址
private static final long BASECOUNT;
23.表示cellsBusy属性在concurrentHashMap中内存便宜地址
private static final long CELLSBUSY;
24.表示cellValue属性在concurrentHashMap中内存便宜地址
private static final long CELLVALUE;
25.表示数组的第一个元素的偏移地址
private static final long ABASE;
26.spread()方法
该方法是进行与位运算
static final int spread(int h) {
//h为key值得hash值,将高16位也参与运算,然后与int最大值进行&运算(效果为将值变为正数,其他位置不变)
//HASH_BITS为int最大值,最高位为0
//HashMap中没有处理为正数的步骤,这里负数有其它含义,查看节点类型
return (h ^ (h >>> 16)) & HASH_BITS;
}