JDK 1.8 ConcurrentHashMap (一) —— initTable

JDK 1.8 的JUC对CurrentHashMap 重新定义后做了很大的变革。我们一点一点来拆解,今天就先说说他的 InitTable 方法

上代码:

ConcurrentHashMap的initTable 初始化方法

关于何时初始化我们后面说Put的时候在讨论,今天就先说说这个InitTable

并发包是如何做到既保证并发安全又保证高性能的呢?

关键知识点:

1、CAS

2、volatile


代码中的高亮部分标记了sizeCtl。

sizeCtl是何物?

看图:

参数sizeCtl


Unsafe的初始化


sizeCtl 默认为0,用来控制table的初始化和扩容操作

        如果sizeCtl 为-1 则说明正在初始化

                -N 表示有N-1个线程正在进行扩容操作


注意:图二中SIZECTL中获取的 sizeCtl的地址偏移值,是在static中初始化的。


get到了关键信息,我们先放一边,继续说init方法


if ((sc =sizeCtl) <0)    

        Thread.yield(); // lost initialization race; just spin

else if (U.compareAndSwapInt(this, SIZECTL, sc, -1))

..... //后续省略



第一步:

                是判断SizeCtl是不是<0  判断是否正在初始化。如果是那就Thread.yield() 实则就只允许一个线程操作,是个自选的操作

第二步:

                U.compareAndSwapInt(this, SIZECTL, sc, -1)  这个cas的判断地址并操作为-1

                unsafe方法中的Cas 判断了地址偏移,(SIZECTL早在static就以初始化好了)

                如果比较为True 那就更新为-1。原子操作保证了安全。(不明白CAS的移步百度查询Unsafe的Cas)

                同时volatile保证了顺序与内存可见性。




总结:在第一步进行判断,是不能保证并发安全的,如果两个线程同时进入,就需要Cas去保证安全,并且原子变更数值

当然sizeCtl 不仅仅在init中使用,还在扩容中使用。纵观整个类会发现大量的Unsafe的方法。虽然官方并不推荐使用,

但是事实证明 Doug Lea 是你大爷,还是你大爷。

你可能感兴趣的:(JDK 1.8 ConcurrentHashMap (一) —— initTable)