put方法
自旋方法;
initTable方法
initTable方法是个while循环,退出条件是数组初始化好了;返回值是初始化好的数组;
sizeCtl最开始的值
将sizeCtl赋值给了一个临时变量sc,两个作用
1)cas操作设置sizeCtl为-1前先判断sizeCtl是否还和sc相等,相等则cas操作可以成功,则可以初始化数组,即以临时变量作为比较依据;
2)存储sizeCtl被修改为-1之前的值,便于在将sizeCtl修改为-1后,判断第一个进入initTable方法的线程sizeCtl最初的大小;sizeCtl最初的大小与用户调用chm构造方法的方式有关,如果用户用的是chm的默认构造函数,则sizeCtl为0,后续将以16作为初始化数组的容量;若用的是有参构造,传入了chm数组“初始化容量x”,则此时在构造函数中会将sizeCtl赋值为不小于x+x/2+1的最小的2的次方数y,此值y才是真正的初始化数组容量;
初始化过程
假设最开始线程A,B同时进入initTable方法,此时的sizeCtl的值只有两种可能,为0或者为y(2的幂),当线程A,B同时进行cas修改sizeCtl为-1,若A线程修改成功,则线程B再次自旋,感知到sizeCtl为-1,则会执行Thread.yield()让出cpu时间片,进入就绪状态,下一刻线程B可能会重新抢到cpu执行权也可能没抢到。若没抢到,则线程A此时会根据sizeCtl初始化数组,随后将sizeCtl的值更新为0.75n(为下次扩容的阈值,达到该值就扩容),n为数组长度,最后退出循环;线程B再次拿到cpu执行权时,发现数组已经初始化好了,最后也退出;
判断(n-1)&hash(key)所在桶位头节点状态
一共有四种情况,如下
头节点为null
cas给该桶位添加一个头节点,cas失败则直接break退出put自旋;
存在头节点且其hash为-1
表示当前桶位是FWD节点,接着当前线程执行helpTransfer方法,协助table迁移数据至新的更大table;
存在头节点且其hash不小于0