最近在看 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 了。。。
1
wuyiccc 1 天前
没看懂。。。
|
2
Hatter OP @wuyiccc 就是理论上不用 volatile 修饰 a 的话,线程内对 a 做了修改,变量 a 的变动对线程 2 和 3 应该是不可见的,理论上线程 2 和 3 就是应该一直死循环才对;但我发现有时候居然能打出来,然后做了一点看起来不相关的修改之后又打印不出来了
|
3
wolfie 1 天前
volatile 是 内存可见性问题,不用 volatile 修饰,不代表永远无变化感知,只是延迟。
|
4
psjay 1 天前
不可见的意思是:不立即可见。
你这个 Demo 用来测试 volatile 没有意义,即便你加了 volatile ,对 a 的访问也无法保证原子性。 |
5
liprais 1 天前
"就是理论上不用 volatile 修饰 a 的话,线程内对 a 做了修改,变量 a 的变动对线程 2 和 3 应该是不可见的"
理论不是这样的 https://jpbempel.github.io/2015/05/26/volatile-and-memory-barriers.html |
8
cloudzhou 1 天前
保证可见性,只是说一定能看到,happens before
但不是说,一直不可见,理论上,随着内存的同步周期变化,是能感知到变化的 |
9
lmq2582609 1 天前 3
你的问题应该和编译器有关。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 内存模型的。 |
10
wangliran1121 23 小时 8 分钟前 1
|
11
Hatter OP @wangliran1121 感谢回复,不懂的东西越来越多了 T T
|