美文网首页
volatile修饰数组或引用对象的问题

volatile修饰数组或引用对象的问题

作者: slowwalkerlcr | 来源:发表于2019-07-10 19:43 被阅读0次
  • 偶然在对项目使用sonarLint扫描的时候,得到警告“Non-primitive fields should not be "volatile"”,意思就是非基本字段不应该用volatile修饰。其原因是volatile修饰对象或数组时,只能保证他们的引用地址的可见性。那么事实是怎样呢?我们修改数组的元素(并非修改引用地址)是否对其他线程可见呢?直接扔代码执行一番。
    1、首先不用volatile修饰array数组,发现“结束”两个字一直没打印出来,程序一直在运行,这没有任何问题,因为线程A修改了 array[0] = 2对线程B不可见
    public static int[] array = new int[10];
    public static void main(String[] args) {
        new Thread(() -> {  //线程A
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                array[0] = 2;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();
        new Thread(()->{   //线程B
            try {
                while (true) {
                    if (array[0] == 2) {
                        System.out.println("结束");
                        break;
                    }
                    //Thread.sleep(10);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

2、当加上volatile修饰array时,WTF。。。“结束”打印出来了,这说明线程A修改array[0] = 2对线程B可见呢?这和我们开始得到的观点矛盾了(volatile只对数组的引用保证可见性,这里只修改了array的元素)

 public static volatile int[] array = new int[10];
    public static void main(String[] args) {
        new Thread(() -> {  //线程A
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                array[0] = 2;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();
        new Thread(()->{   //线程B
            try {
                while (true) {
                    if (array[0] == 2) {
                        System.out.println("结束");
                        break;
                    }
                    //Thread.sleep(10);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
  • 这里stackoverflow给出了比较靠谱的答案链接地址,大概意思就是说当ThreadB读取array时,因为array的引用被volatile修饰,所以ThreadB对所有变量都会从主内存去获取,当然也就包括array[0]。 所以会让人产生误解,以为是volatile修饰的数组保证了其数组的可见性,其实不然。
    image.png 《Java并发编程实战》一书给出的解释如下
    image.png
  • 其实如果不给数组加volatile就永远不会打印结束”,这种绝对的认为是错误的,volatile保证了其变量及时可见性而不会引起线程安全的问题,就算不加volatile,cpu在空闲的时候也会将array[0]的值从线程缓存刷新到主存,只是while(true)太快了,导致cpu一直没空。我们可以使用Thread.sleep(10)让出CPU让其有空将线程变量刷新到主内存中去。记得先去掉volatile修饰
 public static int[] array = new int[10];
    public static void main(String[] args) {
        new Thread(() -> {  //线程A
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                array[0] = 2;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();
        new Thread(()->{   //线程B
            try {
                while (true) {
                    if (array[0] == 2) {
                        System.out.println("结束");
                        break;
                    }
                    Thread.sleep(10);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

我们发现“结束”在没有volatile修饰的时候,一样有办法可以打印出来

image.png

相关文章

  • volatile修饰数组或引用对象的问题

    偶然在对项目使用sonarLint扫描的时候,得到警告“Non-primitive fields should n...

  • JITWatch

    问题1:volatile 修饰数组时能否保证数组元素的可见性? vo...

  • 史上最全Java面试题!关于volatile关键字篇(带全部答案

    可以创建Volatile数组吗? Java 中可以创建 volatile类型数组,不过只是一个指向数组的引用,而不...

  • ts 数据类型

    数据类型 1. 基础类型数据 2. 引用类型 对象和数组对象和数组.png 函数函数修饰词.png

  • Java 中 final 用法释疑与总结

    final 修饰的地方 修饰基础数据成员(修饰含义:该成员修饰为常量,不可修改) 修饰类或对象的引用(修饰含义:改...

  • 深拷贝浅拷贝

    1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用 2.深拷贝: 创建一...

  • nodejs之深拷贝和浅拷贝

    一、定义 1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用 2.深拷贝...

  • 深拷贝与浅拷贝的理解及其实现的方法

    一、概念区分 1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用 2.深...

  • javascript总结:深拷贝与浅拷贝的实现

    浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用 深拷贝: 创建一个新的对...

  • 深拷贝和浅拷贝

    1. 深拷贝和浅拷贝 1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用...

网友评论

      本文标题:volatile修饰数组或引用对象的问题

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