1

因为 volatile 写入后的普通读写不禁止重排序,所以下面代码中的 b=3 可能会在 a=2+b 之前重排序吗?

volatile int a = 1;
int b = 2;

private void demo () {
    a = 2 + b;
    b = 3;
}
4

2 回答 2

1

不完全是。

需要注意的重要一点是,给定两个事件,两个线程可以以不同的顺序观察这两个事件。

由于这两个写入都在一个线程中,因此该线程保证按照它们出现的顺序观察这两个写入。因此,该语句没有风险a = 2 + b将使用即将设置的值b(即 3)而不是其已经设置的值(大概是 2,尽管它显然可以依赖于您未显示的其他代码)。

这意味着a最终将根据需要设置为 4,而不是5。

但是其他线程当然可以观察到这些乱序的写入;如果另一个线程有System.out.println("a = " + this.a + ", b = " + this.b),并且这里没有其他同步,那么该线程绝对有可能打印a = 1, b = 3,显示 的原始值,a但显示 的新值b

于 2021-10-14T17:02:22.203 回答
0

不能违反程序的顺序语义。根据您的问题,我的印象是演示方法是由单个线程执行的,因此 a 的易失性不相关。

如果我将您的代码简化为单独的加载/存储:

r1=b
a=2+r1
b=3

唯一可能的允许结果是 a=4,b=3。

然后 b=3 和 a=2+r1 可以重新排序,因为它不会改变结果。但是如果 b=3 会跳到 r1=b 前面,那么这个执行的结果就是 a=5, b=3。这违反了程序的顺序语义。

有关更多信息,请参阅我在这篇文章中的回答: 为什么 Java Concurrency in Practice 中的这个示例不允许重新排序

于 2021-10-14T17:17:08.583 回答