Java JLS是否允许此指令重新排序?
根据Java语言规范()以下代码段(从Java JLS是否允许此指令重新排序?,java,jvm,memory-model,jls,Java,Jvm,Memory Model,Jls,根据Java语言规范()以下代码段(从A==B==0开始) 。。。可能导致r2==2和r1==1。这是因为执行B=1的结果不取决于是否执行了r2=A,因此JVM可以自由地交换这两条指令的执行顺序。换句话说,规范允许以下交错: Thread 1 Thread 2 -------- -------- B = 1; r1 = B; A = 2; r2 = A; 这显然会
A==B==0
开始)
。。。可能导致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;
其中,obj
是线程之间共享的引用
是否仍然允许对r2=A
和B=1
进行重新排序?
JLS说 但是,如果这不影响独立执行该线程,则允许编译器对任一线程中的指令重新排序 …哪种类型表示指令仍然可以交换。另一方面,以下陈述 监视器上的解锁发生在监视器上的每个后续锁定之前
指示在某些调度下,两个线程中的语句之间可能存在“发生在之前”关系,这可能不允许指令重新排序。非正式地说,这是不允许的。这被称为“蟑螂汽车旅馆模型” 特别是,不能跨同步块移动操作 然而,在形式上,JMM并没有谈到重新排序。在你的例子中,我们只能推断
r2=A
发生在A=2
之前<代码>r2必须为0。但是B=1
和r1=B
之间没有约束<代码>r1可以是0或1r2
可以为0或2因此,该程序仍然包含数据竞争;然而,我们可以推断
(r1,r2)
只能是(0,0),(1,0),(0,2);不可能是(1,2)这是否取决于监控代码?如果我理解正确的话,这些监控行无论如何都可以优化,因为零代码至少在理论上没有影响和重叠。如果它们不影响语义,那么当然,它们可能会被删除。但是如果它们阻止指令重新排序,它们确实会影响语义,对吗?是的,我就是这样理解第一个qouted语句的:即使被监视的块被重新排序执行,语义在独立执行中也不会改变。第二种说法是,锁所有权的转换是无缝的。我对整个重新排序的理解如下:重新排序仅限于语义。连锁没有不良影响。但指令重新排序在应用于代码时会导致(甚至更多)未定义的行为,代码共享变量而没有任何联锁机制。
Thread 1 Thread 2
-------- --------
r2 = A; r1 = B;
monitorenter obj monitorenter obj
monitorexit obj monitorexit obj
B = 1; A = 2;