BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #62771同步于 2019/9/30
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

【问题】关于volatile关键字的一个问题

a1020076136
2019/9/30镜像同步17 回复
经测试,打开注释行,子线程就不会陷入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; } } ```
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
a2012210456机器人#1 · 2019/9/30
马一下
huxuesong09机器人#2 · 2019/9/30
好神奇,mark 一下
xuanyu66机器人#3 · 2019/9/30
就是看会不会引起刷新内存呗。你把system.out那一句放到循环里也会引起内存刷新结束。或者thread.yield。 所以才需要volatile关键字,显式地表现它的可见性
a1020076136机器人#4 · 2019/9/30
嗯,你说的有道理,不纠结这种非volatile变量的可见性了 【 在 xuanyu66 (angry_yang) 的大作中提到: 】 : 就是看会不会引起刷新内存呗。你把system.out那一句放到循环里也会引起内存刷新结束。或者thread.yield。 : 所以才需要volatile关键字,显式地表现它的可见性
cc19931002机器人#5 · 2019/9/30
道理是有道理,这种线程切换后面的上下文切换会把线程本地的缓存清空掉,再切回来的时候重新去捞一边变量。所以能跳出循环是符合预期的。但是为什么再你的demo里面没有上下文切换的时候非volatile类型变量也变得可见了呢? 【 在 a1020076136 的大作中提到: 】 : 嗯,你说的有道理,不纠结这种非volatile变量的可见性了
a1020076136机器人#6 · 2019/9/30
网上有类似的问题,有个说法是,对于非volatile变量,jvm没有对它做出可见性的保证,所以也不确定它何时可见,不要针对随机性进行编程,必要的时候用volatile显式保证可见。我的demo虽然运行的结果每次都一样,但是不保证永远是这样,不知道这样解释对不对 【 在 cc19931002 (啦啦) 的大作中提到: 】 : 道理是有道理,这种线程切换后面的上下文切换会把线程本地的缓存清空掉,再切回来的时候重新去捞一边变量。所以能跳出循环是符合预期的。但是为什么再你的demo里面没有上下文切换的时候非volatile类型变量也变得可见了呢?
cc19931002机器人#7 · 2019/9/30
这个话没有错,但是这个话感觉不痛不痒。。。不知道是不是jvm再这块实现做了一些特殊处理,比如更新volatile的修饰的变量的时候,顺带把局部变量表里面的所有变量都更新了一此 【 在 a1020076136 的大作中提到: 】 : 网上有类似的问题,有个说法是,对于非volatile变量,jvm没有对它做出可见性的保证,所以也不确定它何时可见,不要针对随机性进行编程,必要的时候用volatile显式保证可见。我的demo虽然运行的结果每次都一样,但是不保证永远是这样,不知道这样解释对不对
a1020076136机器人#8 · 2019/9/30
反正,规范上是没见讲的,也可能我没看到,就不管它了哈哈,说不定之后会有大佬来解释一波 【 在 cc19931002 (啦啦) 的大作中提到: 】 : 这个话没有错,但是这个话感觉不痛不痒。。。不知道是不是jvm再这块实现做了一些特殊处理,比如更新volatile的修饰的变量的时候,顺带把局部变量表里面的所有变量都更新了一此
nuanyangyang机器人#9 · 2019/10/12
这样解释: 如果不加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