Java编译器或JVM能否交换独立指令的指令顺序?

Java编译器或JVM能否交换独立指令的指令顺序?,java,compiler-construction,jvm,instructions,Java,Compiler Construction,Jvm,Instructions,让我们看一下下面的陈述: int d0, d1; int[] ds = {0, 0}; 现在,一个线程有以下说明: d0++; d1++; 而另一个线程有此指令: ds[1] = d1; ds[0] = d0; 如果我们并行运行这些线程,ds显然可以有三种组合:{0,0}、{1,1}和{1,0} 现在最大的问题是:是否也存在{0,1}?编译器/JVM是否可以简单地交换指令,因为它认为它们不相关?如果是,这种行为的“规则”到底是什么?这取决于编译器还是JVM?是的,{0,1}。在这种情况下,

让我们看一下下面的陈述:

int d0, d1;
int[] ds = {0, 0};
现在,一个线程有以下说明:

d0++;
d1++;
而另一个线程有此指令:

ds[1] = d1;
ds[0] = d0;
如果我们并行运行这些线程,
ds
显然可以有三种组合:{0,0}、{1,1}和{1,0}


现在最大的问题是:是否也存在{0,1}?编译器/JVM是否可以简单地交换指令,因为它认为它们不相关?如果是,这种行为的“规则”到底是什么?这取决于编译器还是JVM?

是的,
{0,1}
。在这种情况下,Java内存模型不足以保证排序。这甚至不需要指令重新排序——如果在x86或x86_64以外的任何设备上运行该程序,无论如何都会发生这种情况

这里要明确的是,实际的CPU硬件将对这些加载和存储进行重新排序,但如果是x86,则不会


请参阅

是,编译器和jvm(即时编译器)都可以执行指令重新排序。此外,硬件处理器也可以做到这一点。为了防止不必要的重新排序,应该使用。如果没有适当的同步,这确实是可能的

Java语言规范在第17章中定义了多线程Java程序的语义。这一章很难理解,但它确实包含了人们可以依赖的官方规则。特别是,它:

内存模型描述给定一个程序和该程序的执行跟踪,该执行跟踪是否是该程序的合法执行。Java编程语言内存模型的工作原理是检查执行跟踪中的每个读操作,并根据特定规则检查该读操作观察到的写操作是否有效

内存模型描述程序的可能行为。一个实现可以自由地生成它喜欢的任何代码,只要程序的所有结果执行产生的结果可以由内存模型预测

为了提供一个粗略的概述,内存模型定义了一个必须重新排序的定义。为不同线程执行的操作建立之前发生的事件的通常方法是对这些操作进行处理,例如使用
synchronized
块或写入或读取volatile变量

在没有这种同步的情况下,运行时将独立执行线程,允许当前线程无法观察到的任何重新排序


也就是说,如果您有可变的共享状态,通常需要同步访问它的线程。

如果优化的行为与串行(iow,单线程)模型中的未优化代码相同,则通常认为是安全的。除非相关的语言构造对线程有明确的规定