Java 内存模型中线程发散动作和外部动作的示例

Min*_*ock 3 java java-native-interface multithreading native java-memory-model

我目前正在学习 Java 内存模型,并且了解了不同类型的Actions

其中有两个我不完全理解:

  • 外部行动
  • 线程发散动作

请解释这两种操作类型并举例说明它们以及它们关于编译器重新排序发生在关系之前的特殊属性。哦,本地调用也是外部操作吗?

我认为如果它们没有什么特别之处,它们就不会定义线程发散动作。那么是什么让它们与众不同,以至于需要将它们定义为一种特殊的动作呢?

Raf*_*ter 5

现有答案已经正确定义了这些操作是什么。

至于重新排序:请看以下线程发散操作的示例:

class ThreadDivergence { 

  int foo = 0; 

  void thread1() { 
    while (true); // thread-divergence action
    foo = 42; 
  } 

  void thread2() { 
    assert foo == 0; 
  } 
}
Run Code Online (Sandbox Code Playgroud)

你会期望这个断言永远不会失败。如果没有线程发散操作,则无法保证这一点,因为无法访问设置的定义foo = 42可以重新排序以首先执行。这是 JMM 禁止的。

同样,添加外部操作以避免出现意外结果:

class Externalization { 

  int foo = 0; 

  void method() { 
    jni(); // external action
    foo = 42; 
  } 

  native void jni(); /* { 
    assert foo == 0; 
  } */ 
}
Run Code Online (Sandbox Code Playgroud)

假设实现了 JNI 方法来运行相同的断言,您不会期望这会失败。JIT 编译器无法确定任何外部结果,以至于 JMM 也禁止此类重新排序。