根据 Java 语言规范(示例 17.4-1),以下代码段(从 开始A == B == 0
)...
Thread 1 Thread 2
-------- --------
r2 = A; r1 = B;
B = 1; A = 2;
... 可能导致r2 == 2
和r1 == 1
。这是因为执行的结果B = 1;
不取决于是否r2 = A
已经执行,因此JVM可以自由地交换这两条指令的执行顺序。换句话说,规范允许以下交织:
Thread 1 Thread 2
-------- --------
B = 1;
r1 = B;
A = 2;
r2 = A;
这显然导致r2 == 1
和r1 == 1
。
我的问题:
假设我们稍微调整一下这个例子:
Thread 1 Thread 2
-------- --------
r2 = A; r1 = B;
monitorenter obj monitorenter obj
monitorexit obj monitorexit obj
B = 1; A = 2;
whereobj
是线程之间共享的引用。
r2 = A
重新排序是否B = 1
仍然允许?
JLS 说……
但是,允许编译器对任一线程中的指令重新排序,只要这不会影响该线程的单独执行。
...这表明指令仍可能被交换。另一方面,以下声明
监视器上的解锁发生在该监视器上的每个后续锁定之前。
表明在某些调度下,我们可能在两个线程中的语句之间存在发生前的关系,这可能不允许指令重新排序。