美文网首页
JDK 1.8 ConcurrentHashMap (一) ——

JDK 1.8 ConcurrentHashMap (一) ——

作者: John_CC | 来源:发表于2019-04-03 11:41 被阅读0次

    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 (一) ——

          本文链接:https://www.haomeiwen.com/subject/ytjabqtx.html