返回信息流经测试,打开注释行,子线程就不会陷入while死循环了,为什么呢
```
public class VolatileTest3 {
// b使用volatile修饰
public static volatile long b = 0;
//消除缓存行的影响
public static long a1,a2,a3,a4,a5,a6,a7,a8;
// c不使用volatile修饰
public static long c = 0;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while (c == 0) {
//long x = b;
}
System.out.println("c=" + c);
}).start();
Thread.sleep(100);
b = 1;
c = 1;
}
}
```
这是一条镜像帖。来源:北邮人论坛 / java / #62771同步于 2019/9/30
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
【问题】关于volatile关键字的一个问题
a1020076136
2019/9/30镜像同步17 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
就是看会不会引起刷新内存呗。你把system.out那一句放到循环里也会引起内存刷新结束。或者thread.yield。
所以才需要volatile关键字,显式地表现它的可见性
嗯,你说的有道理,不纠结这种非volatile变量的可见性了
【 在 xuanyu66 (angry_yang) 的大作中提到: 】
: 就是看会不会引起刷新内存呗。你把system.out那一句放到循环里也会引起内存刷新结束。或者thread.yield。
: 所以才需要volatile关键字,显式地表现它的可见性
道理是有道理,这种线程切换后面的上下文切换会把线程本地的缓存清空掉,再切回来的时候重新去捞一边变量。所以能跳出循环是符合预期的。但是为什么再你的demo里面没有上下文切换的时候非volatile类型变量也变得可见了呢?
【 在 a1020076136 的大作中提到: 】
: 嗯,你说的有道理,不纠结这种非volatile变量的可见性了
网上有类似的问题,有个说法是,对于非volatile变量,jvm没有对它做出可见性的保证,所以也不确定它何时可见,不要针对随机性进行编程,必要的时候用volatile显式保证可见。我的demo虽然运行的结果每次都一样,但是不保证永远是这样,不知道这样解释对不对
【 在 cc19931002 (啦啦) 的大作中提到: 】
: 道理是有道理,这种线程切换后面的上下文切换会把线程本地的缓存清空掉,再切回来的时候重新去捞一边变量。所以能跳出循环是符合预期的。但是为什么再你的demo里面没有上下文切换的时候非volatile类型变量也变得可见了呢?
这个话没有错,但是这个话感觉不痛不痒。。。不知道是不是jvm再这块实现做了一些特殊处理,比如更新volatile的修饰的变量的时候,顺带把局部变量表里面的所有变量都更新了一此
【 在 a1020076136 的大作中提到: 】
: 网上有类似的问题,有个说法是,对于非volatile变量,jvm没有对它做出可见性的保证,所以也不确定它何时可见,不要针对随机性进行编程,必要的时候用volatile显式保证可见。我的demo虽然运行的结果每次都一样,但是不保证永远是这样,不知道这样解释对不对
反正,规范上是没见讲的,也可能我没看到,就不管它了哈哈,说不定之后会有大佬来解释一波
【 在 cc19931002 (啦啦) 的大作中提到: 】
: 这个话没有错,但是这个话感觉不痛不痒。。。不知道是不是jvm再这块实现做了一些特殊处理,比如更新volatile的修饰的变量的时候,顺带把局部变量表里面的所有变量都更新了一此
这样解释:
如果不加volatile,java编程语言的java memory model允许一个线程读到另一个线程任何一次写进去的值(可以是初值0也可以是主线程写入的1),只要不是happens-after它的就可以。但这个程序两个线程没有任何同步,所以没有任何happens-before关系。所以,就算主线程写,另一个线程永远读到c == 0,也是允许的。只要允许,你看到的“程序永远退不出去”就是合理的结果。至于为什么会出现这种现象,你暂且认为是巧合吧,反正这是《Java语言标准》允许的,JVM没做错什么。
但是一旦加上volatile,所有线程对c的读写操作就构成一个序列。因为main早晚会执行完,所以早晚会又一个对c的写操作,写入1。由于new thread会不断读c,早晚会有一次读happens after那个往c里写1的操作。对于volatile变量来说,写之后的读都能看到那个写的值“1”。所以那个new thread早晚可以看到c == 1。
关键词:“happens-before”。
参考资料:《java language specification》里的java memory model