美文网首页java进阶干货程序员
如何保证数组元素的可见性

如何保证数组元素的可见性

作者: 美团Java | 来源:发表于2018-03-22 15:00 被阅读1415次

    问题

    之前有小伙伴在星球提了这么一个问题

    这篇文章时隔一两年,突然看到还是有点印象,文章中,我只是强硬的抛出了一个结论:虽然table变量被volatile修饰了,但里面的元素并没有volatile修饰,无法保证元素的可见性。

    但是这种解释,似乎被众多的小伙伴怀疑,也一直没有找到有理的证据(基础还是太弱)

    不过在星球中,大家还是很积极的讨论,虽然有些是错的(这种问题在大部分人身上都有,你不表现出来,那你永远不知道自己所掌握的东西其实是不对的)

    解惑

    在ConcurrentHashMap(1.8)中,内部使用一个volatile的数组table保存数据,细心的同学可以发现,Doug Lea每次在获取数组的元素时,采用Unsafe类的getObjectVolatile方法,在设置数组元素时,采用compareAndSwapObject方法,而不是直接通过下标去操作,这是为什么?

    今天得到R大的确认:这个是因为Java数组在元素层面的元数据设计上的缺失,无法表达元素是final、volatile等语义,所以开了后门,使用getObjectVolatile用来补上无法表达元素是volatile的坑,@Stable用来补上final的坑,数组元素就跟没有标volatile的成员字段一样,无法保证线程之间可见性。

    只有触发happens before关系的操作,才能保证线程之间的可见性,比如使用table[0] = new Object()直接赋值,这个赋值不会触发任何happens before关系的操作,相当于对一个无volatile变量进行赋值一样。

    加入知识星球,不仅可以查漏补缺,还可以验证自己对Java的理解。
    目前已有260+小伙伴加入。

    相关文章

      网友评论

      • 陈同学_3207:楼主测试过吗?
        测试之后数组元素是volatile的
        是我的测试方法有问题吗?
        public class work2 {
        public static void main(String[] args)
        {
        try
        {
        Test t = new Test();
        t.start();
        Thread.sleep(2000);
        t.setRunning(false);
        System.out.println("已赋值为false");
        }
        catch (InterruptedException e)
        {
        e.printStackTrace();
        }
        }
        }
        class Test extends Thread
        {
        private volatile boolean[] isRunning = new boolean[10];

        public Test(){
        isRunning[0]=true;
        }

        public void setRunning(boolean isRunning)
        {
        this.isRunning[0]=isRunning;

        }

        public void run()
        {
        System.out.println("进入run了");
        while (isRunning[0]== true){};
        System.out.println("线程被停止了");
        }
        }
      • 刘志磊LJ:您好,对于您上面的解惑,我是不是可以认为对于concurrenthashmap,每个线程都能获取到最新的table元素呢:joy:
      • 刘志磊LJ:“数组元素就跟没有标volatile的成员字段一样,无法保证线程之间可见性”
        引用这句话,请问一下如果是copyonwritearrayist,也不能保证每次get都是最新的元素吗,即便数组也同样被volatile修饰
      • 4eadb3ef44df:getObjectVolatile强制每次都拿到最新的值,compareAndSwapObject使用无锁进行修改操作,分别对应锁的可见性和原子性语意
      • 0701fa97be25:我理解的是数组在java中是一个特殊的对象,对象引用设置volatile,并不能保证内部元素的volatile语义(内存可见性,更新缓存会使得其他CPU核的缓存行失效)。所以只能通过Unsafe.putObjectVolatile来保证设置对象的volatile语义。
      • HoldGone:r大是谁呢😊
        MinamiSun:RednaxelaFX,做jvm开发的人,技术很厉害。
        西瓜君zody:R大都没听过?

      本文标题:如何保证数组元素的可见性

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