请教一个 Java volatile 字段可见性的问题

2020-05-17 19:05:50 +08:00
 dengsq

看一个讲解 volatile 可见性教学视频的时候,发现视频中的代码和我运行的效果不太一样,有些困惑。

代码大致如下: https://gist.github.com/dsq123/e57514ca51c875b75d0ea311bb556d92

视频中运行的效果是: 1.number 字段不加 volatile,主线程的循环会一直运行,读不到 number 字段的改变。 2.而加了 volatile 后,number 字段就可见了,程序则会正常结束。

我测试的效果是,不加 volatile 关键字的情况下,主线程依旧可以获取到 AAA 线程对 number 的修改,这是为何?

2398 次点击
所在节点    Java
12 条回复
luozic
2020-05-17 19:21:04 +08:00
System.out.println 对这个有影响
luozic
2020-05-17 19:22:34 +08:00
yanshenxian
2020-05-17 19:42:33 +08:00
@luozic 感觉不太对 我本地没有复现题主所说的 不加 volatile 主线程可以获取到 AAA 线程对 number 修改的情况
dengsq
2020-05-17 19:47:17 +08:00
@luozic 确实是这样,是 System.out.println 所影响的。
dengsq
2020-05-17 19:48:45 +08:00
@yanshenxian 是我的疏忽,我测试时,在主线程的循环里打印了日志,所以读到了其他线程的改动。 然而我贴代码的时候,把主线程的 Sout 删掉了=。=
yanshenxian
2020-05-17 19:53:21 +08:00
@dengsq get 了
Jooooooooo
2020-05-17 20:11:42 +08:00
不写 volatile 行为不定义
dengsq
2020-05-17 23:49:50 +08:00
@luozic @yanshenxian @Jooooooooo 还想请教一个问题:
有一种场景是 [A 线程指令重排导致 B 线程出错] ,如 A 改变了 boolean flag = true/false,而 B 线程需要根据 flag 处理逻辑。

既然 volatile 可以保证变量的可见性,那么不加 volatile 时,不同线程之间的变量应该是不可见的。

这样的话,也就不会出现指令重排的问题呀?
Jooooooooo
2020-05-17 23:56:36 +08:00
@dengsq 没看懂你说的问题是啥.

"不加 volatile 时,不同线程之间的变量应该是不可见的" 这句不对. 只能说行为不定义, 可不可见取决于 cpu 的行为, 举个例子. 如果当时机器因为干别的活把当前核给让出做上下文切换了, 这个值就是可见的了

更极端的例子, 你到一个单线程的机器上跑这个代码, 不会出现不可见的问题
momocraft
2020-05-18 00:02:43 +08:00
保证可见的反面是 "不保证" 不是 "保证不"
dengsq
2020-05-18 00:23:04 +08:00
@Jooooooooo @momocraft 结合二位的回答我就明白了,是我的理解有问题,取反取错了。
非常感谢😄
ArronJun
2020-05-19 08:10:43 +08:00
打印方法加了同步关键字

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/672640

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX