请教下 Java 的 volatile 以及一点多线程的疑问

2 天前
 Hatter

最近在看 java 的 volatile 这个东西,写了一块代码想测试一下,代码如下:

我的理解是,如果变量 a 没有 volatile 修饰,那么理论上就应该线程 1 打印一次,其他线程空转不再打印

但目前发现有一些情况:

1 、如果不加 Thread.sleep 这行代码,程序能直接打印到 100 ,加了 sleep 才是死循环

2 、去掉 sleep ,但把打印语句换成 System.out.println(Thread.currentThread().getName()+":"+su.getA()); 结果也会变成死循环

所以想请教下 v 友两个问题

1 、为什么我没加 volatile 也能打印到 100

2 、为什么换了个输出语句就又打印不到 100 了。。。

1176 次点击
所在节点    Java
11 条回复
wuyiccc
2 天前
没看懂。。。
Hatter
2 天前
@wuyiccc 就是理论上不用 volatile 修饰 a 的话,线程内对 a 做了修改,变量 a 的变动对线程 2 和 3 应该是不可见的,理论上线程 2 和 3 就是应该一直死循环才对;但我发现有时候居然能打出来,然后做了一点看起来不相关的修改之后又打印不出来了
wolfie
2 天前
volatile 是 内存可见性问题,不用 volatile 修饰,不代表永远无变化感知,只是延迟。
psjay
2 天前
不可见的意思是:不立即可见。
你这个 Demo 用来测试 volatile 没有意义,即便你加了 volatile ,对 a 的访问也无法保证原子性。
liprais
2 天前
"就是理论上不用 volatile 修饰 a 的话,线程内对 a 做了修改,变量 a 的变动对线程 2 和 3 应该是不可见的"
理论不是这样的
https://jpbempel.github.io/2015/05/26/volatile-and-memory-barriers.html
Hatter
2 天前
@psjay 是我对不可见的理解有问题了。。多谢
原子性这块倒是明白,并不是想测试原子性相关的情况
Hatter
2 天前
@liprais 多谢老哥,还是搞错了“是不是”的问题
cloudzhou
2 天前
保证可见性,只是说一定能看到,happens before
但不是说,一直不可见,理论上,随着内存的同步周期变化,是能感知到变化的
lmq2582609
2 天前
你的问题应该和编译器有关。java 好像在 1.8 开始就默认使用分层编译了。
它编译的大概步骤是:解释阶段 -> C1 编译器 -> C2 编译器
如果你只使用 C1 编译器的话代码执行是没有问题的,你可以增加 VM 参数尝试:-XX:TieredStopAtLevel=3 。因为 C1 编译器的 level 是 1 ,2 ,3 ,所以设置-XX:TieredStopAtLevel 不超过 3 ,就不会使用 C2 编译器。
如果你只想使用 C2 编译器,你可以设置-XX:TieredStopAtLevel=4 。不过默认就会启动,可以不必尝试了。
当然,对于 volatile 的处理,C1 和 C2 都是遵循 java 内存模型的。
wangliran1121
2 天前
Hatter
1 天前
@wangliran1121 感谢回复,不懂的东西越来越多了 T T

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

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

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

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

© 2021 V2EX