通过JVM / JIT插入Fence指令

时间:2011-07-12 17:42:22

标签: java memory-model java-memory-model

Java内存模型提供DRF保证(数据竞争自由),这意味着在轻松的内存模型下执行时,数据竞争免费程序将提供与顺序一致执行相同的行为。我有以下问题: a)给定一个racy程序,编译器(非常具体的任何jvm实现)是否进行延迟集分析/线程转义分析等,以找出需要插入的栅栏指令以使其无竞争?或者是JIT根据执行的位置来做它?

b)如果编译器这样做(在这种情况下为jvm)为什么我们只能编写racy程序,因为编译器无论如何都要将其转换为无竞赛程序?如果编译器以任何方式去做(通过栅栏插入使其无竞争),那么如何编写racy程序(故意),就像java中并发数据结构的一些实现一样?

c)或者第三种可能性,即jvm本身不会将racy转换为无种族计划,但是存在可以为我们做的其他分析。是这样的吗?

1 个答案:

答案 0 :(得分:3)

  

鉴于一个racy程序,编译器(非常具体的任何jvm实现)是否进行延迟集分析/线程转义分析等,以找出需要插入的栅栏指令以使其无竞争?或者是JIT根据执行的位置来做它?

内存栅栏指令特定于架构的指令集。它们不是JVM指令集中的等效指令。因此,JVM / JIT实际上是向处理器发出fence指令。

  

如果编译器这样做(在这种情况下为jvm)为什么我们只能编写racy程序,因为编译器无论如何都要将它转换为无竞赛程序?如果编译器以任何方式去做(通过栅栏插入使其无竞争),那么如何编写racy程序(故意),就像java中并发数据结构的一些实现一样?

编译器只会确保在生成字节代码时,对JVM中的变量执行的所有操作都遵循Java内存模型中指定的规则。具体而言,在优化领域,编译器可以自由地优化任何指令集,只要它不影响操作之间必须存在的先发生关系或操作之间的同步顺序。例如,编译器不会重新组织对volatile变量的读写操作。它还将确保在进入或离开保护(同步)代码区域时不会违反关系之前发生。

因此,编译器将“racy”程序转换为无竞赛程序的声明是不正确的。实际上,假设无竞争(但不是在Java内存模型下)的程序在优化后可能会成为一个“活泼”的程序。

Java中数据结构的并发实现依赖于Java内存模型提供的保证。具体来说,这是来自Java 5的修订后的Java内存模型,其中准确地指定了易失性变量的读写之间的发生之前的关系。 java.util.concurrent包中的ConcurrentXXX类在很大程度上依赖于挥发性读取的承诺行为,以确保无竞争行为。在Java内存模型下,如果这是程序顺序,则保证在读取之前发生对volatile变量的写入;换句话说,易失性读取将始终检索变量中最准确的数据版本。并发类利用它来确保数据结构可以由单个线程更新,同时被多个其他线程读取(在任何其他情况下,都会有竞争条件)。

  

或者jvm本身不会将racy转换为无种族计划的第三种可能性,但是存在可以为我们做的其他分析。是这样的吗?

JVM发出内存栅栏指令。它不会将“活泼”程序转换为“无竞赛”程序。如果编译器生成了服从Java内存模型的字节码,那么JVM / JIT将在必要时发出内存栅栏指令 - 读取/写入volatile变量,获取或释放对象上的监视器等。

冒着重复自己的风险,JVM和编译器都不会将“racy”程序转换为无竞赛程序,反之亦然。任何相反的行为都是Java内存模型或JVM中的错误。通过了解程序顺序,同步顺序和先前发生的顺序,您将需要将程序编写为无竞争程序,并且编译器和JVM将保证在运行时确保它。

我建议您阅读this article at InfoQ,了解有关JVM如何发布内存栏指令并保证Java内存模型所做出的承诺的更多详细信息。