Java内存模型中外部操作的重新排序
我目前正在学习Java内存模型,以及它如何影响编译器可能进行的重新排序。然而,我对外部操作有点困惑。JMM将它们定义为一种可以在on操作之外观察到的操作。我理解外部行为是指打印值、写入文件、网络操作等 现在,外部操作如何受到重新排序的影响?我认为很明显,一个外部操作不能与另一个外部操作重新排序,因为这将改变程序的可观察行为(因此根据JMM,这不是有效的转换)。但是,如何使用正常内存访问或同步操作重新排序外部操作呢?例如:Java内存模型中外部操作的重新排序,java,concurrency,memory-model,java-memory-model,Java,Concurrency,Memory Model,Java Memory Model,我目前正在学习Java内存模型,以及它如何影响编译器可能进行的重新排序。然而,我对外部操作有点困惑。JMM将它们定义为一种可以在on操作之外观察到的操作。我理解外部行为是指打印值、写入文件、网络操作等 现在,外部操作如何受到重新排序的影响?我认为很明显,一个外部操作不能与另一个外部操作重新排序,因为这将改变程序的可观察行为(因此根据JMM,这不是有效的转换)。但是,如何使用正常内存访问或同步操作重新排序外部操作呢?例如: volatile int v = 5; int x = v; System
volatile int v = 5;
int x = v;
System.out.println("!");
打印和int x=v
是否可以在此处重新排序?我看不出它在改变行为,但volatile v的读取与监视器采集相同,因此我认为重新排序是无效的。添加了外部操作以避免意外结果:
class ExternalAction {
int foo = 0;
void method() {
jni();
foo = 42;
}
native void jni(); /* {
assert foo == 0;
} */
}
假设JNI方法是为了运行相同的断言而实现的,您不会期望它失败。JIT编译器无法确定任何外部操作的结果,因此JMM也禁止此类重新排序。我的理解(可能有缺陷)是,在受保护的操作方面没有优先级。因此,volatile读取和外部写入都不能重新排序,因此您的3行示例保持不变。您可以通过将它粘贴到方法中并调用它几(十万?)次来测试它,同时使用-server和-XX:+printcomployment并比较JIT结果。