static int x = 0;
volatile static int y = 0;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (x == 0) {
}
}).start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
log.debug("改变值");
x = 1;
y = 1;
}).start();
}
上面代码 y变量加了volatile,x没有,一个线程一直循环判断x的值
另一个线程3s后改变x和y的值,我看好多例子说第二个线程改变x的值由于volatile的传递性,前一个线程对于x的写是可见的,也就是说第一个死循环会结束。
但是实际测试发现不会停下来
这是为什么呢?
亲,你再好好看看volatile你加在x上了,还是y上了...
经过今天的测试 我有点理解了这个传递性的意思了 上面这个例子是不对的 这里我新贴一段代码
1 static int x = 0;
2 volatile static int y = 0;
3
4 public void actor1(I_Result r) {
5 while (y == 0) { //B部分 //C部分
6
7 }
8 r.r1 = x + y; //C部分
9 }
10
11 public void actor2(I_Result r) {
12 x = 1;//A部分
13 y = 1;//A部分 //B部分
14 }
x变量无volatile修饰
y变量有volatile修饰
这里,我把这段代码重点标记三个部分
A部分:12行+13行
B部分:13行+5行
C部分:5行+8行
假设线程t1 执行actor1方法,线程t2,执行actor2方法
先看A部分,由于y变量有volatile修饰,所以A部分的12行和13行不会发生指令重排
再看B部分,由于y变量有volatile修饰,第5行的while循环在y的值改变后一定会读取到最新的1,导致while循环结束。
再看C部分,当程序运行到第8行,获取x+y的结果时,这个结果会是几?
问题已经有了,我们先分析 首先这个y一定是1,因为程序能执行到第8行时,y的值必定不是0了。这是肯定的。那么现在的问题就是x是几
结果是x一定是1
原因就是 volatile具有传递性,如果 x hb-> y 并且 y hb-> z 那么有 x hb-> z ,配合 volatile 的防指令重排
分析一下:
也就是说当t2的y=1对t1线程可见,那么t2的x=1也一定对t1可见,所以x+y结果一定是2。
但是 如果把actor2方法x,y的赋值顺序颠倒
public void actor2(I_Result r) {
y = 1;//A部分 //B部分
x = 1;//A部分
}
A部分就不符合 x hb-> y ,传递性被破坏,那么C部分读取的x的值就有可能是0。
分析结束,测试一下,这里我就直接上结果了
确实有几率出现x+y=1的情况,说明x的值读取到0的情况。证实了volatile传递性。
如有问题,请指出,我也是刚学习多线程的小白