Java ConcurrentHashMap初始化
我目前正在阅读jdk1.8中ConcurrentHashMap的源代码,我发现Java ConcurrentHashMap初始化,java,concurrency,concurrenthashmap,Java,Concurrency,Concurrenthashmap,我目前正在阅读jdk1.8中ConcurrentHashMap的源代码,我发现initalTable()方法有点让人困惑 公共类ConcurrentHashMap扩展了AbstractMap 实现ConcurrentMap,可序列化{ //某些字段在该方法中旋转 瞬态易失性节点[]表; 私有瞬态volatile int sizeCtl; 私有最终节点[]initTable(){ 节点[]选项卡;int sc; while((tab=table)==null | | tab.length==0){
initalTable()
方法有点让人困惑
公共类ConcurrentHashMap扩展了AbstractMap
实现ConcurrentMap,可序列化{
//某些字段在该方法中旋转
瞬态易失性节点[]表;
私有瞬态volatile int sizeCtl;
私有最终节点[]initTable(){
节点[]选项卡;int sc;
while((tab=table)==null | | tab.length==0){
如果((sc=sizeCtl)<0)
Thread.yield();//丢失了初始化竞争;只需旋转
否则如果(U.compareAndSwapInt(此,SIZECTL,sc,-1)){
试一试{
如果((tab=table)==null | | tab.length==0){
int n=(sc>0)?sc:默认容量;
@抑制警告(“未选中”)
节点[]nt=(节点[])新节点[n];//位置1
table=tab=nt;//位置2
sc=n-(n>>>2);
}
}最后{
sizeCtl=sc;
}
打破
}
}
返回选项卡;
}
}
所以主要的困惑主要集中在以下几点:
while((tab=table)==null | | tab.length==0)
来检查table
是否为null,其长度是否为0,并确定是否继续循环,因此它仅在这两个条件都为false时才退出。我无法想象表
不是null而是长度为0的情况,因为它是在else if
块中初始化的,其中n的值总是大于0。那为什么我们需要两者而不是一个呢else if
块如果前一个线程没有达到table
或place 2的初始化点,也没有更新sizeCtl
,那么第二个线程将能够进入else if
块,那么table
字段将再次初始化?这种情况会在罕见的情况下发生吗?我知道这不会影响程序的正确性,但在某些情况下会发生吗
希望任何人都能给我一个澄清。提前谢谢
更新:
我忘记了一个事实,一个成功的CAS操作将把
sizeCtl
交换为-1,这将阻止其他线程进入else if
块,但是我仍然不清楚为什么我们在if
和中需要两个条件,而单独分析方法initTable
是不够的。您需要考虑其他也可以修改表
和sizeCtl
字段的方法。在那里,您会注意到,例如,transfer
使用CAS将sizeCtl
减少一个。我不确定这是否会在任何时间点导致table.length==0
,但请注意,整个过程要复杂得多,并且initTable
可以与resize操作同时调用。compareAndSwap是原子的;该检查确保只有一个线程可以进入该块。@LouisWasserman感谢您的提示,是的,我忘记了交换,如果一个线程进入块sizeCtl
已交换为-1,那么阻止其他线程进入该块,对吗?但是第一点呢?你能帮我照一下吗?