1

题目描述

volatile修饰对象和数组时,只是保证其引用地址的可见性,可为什么我加了volatile之后下面的代码会马上打印“结束”,如果不给数组加volatile就永远不会打印。volatile修饰对象和数组时,线程对其域或元素操作的详细步骤是什么?求大神指点

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)
public class b {

public static volatile int[] ints = new int[5];
public static void main(String[] args) throws Exception {
    Object o = new Object();
    new Thread(() -> {
        //线程A
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       ints[0] = 2;
    }).start();
    new Thread(() -> {            //线程B
        while (true) {
            if (ints[0] == 2) {
                System.out.println("结束");
                break;
            }
        }
    }).start();
}

}

2018-12-11 提问

查看全部 3 个回答

1

先放一张图:
clipboard.png

首先如果不给数组加volatile就永远不会打印这个理解是错误的,就算不加volatile,cpu在空闲的时候也会将int[0]的值从线程缓存刷新到主存,只是while(true)太快了,导致cpu一直没空。你可以试试看加一行代码后是什么结果:

if (ints[0] == 2) {
    System.out.println("结束");
    break;
}
System.out.println("waiting");

因为System.out.pringln()源码中有synchronized关键字,是很耗时的,这时候cpu就有空去刷新int[0]的值到主存了了。
volitile的作用就是强制将int[0]的值刷新到主存中,保证其在各个线程中的可见性。
over

1

题主好像问的是volatile是否对数组的所有元素都有效这么一个意思

代码宇宙 · 2018年12月12日

展开评论

推荐答案

4

已采纳

我把题主的问题在stackoverflow上问了一下,问题连接,有人也给出了比较靠谱的答案:

clipboard.png

然后我又在《Java并发编程实战》一书中找到了与上面结论类似的描述:(3.1.4节)

clipboard.png

不清楚什么原理,我就用结论解释一波,ThreadA在读取ints[0]时,首先要读取ints引用,这个引用是volatile修饰的,在读取这个ints引用时,所有变量都会从主存读取,其中就包含ints[0]

推广链接