为什么这段代码会失败?

Jan*_*nda 2 java multithreading java-threads

在回顾这个问题时,我注意到了这段代码:

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}
Run Code Online (Sandbox Code Playgroud)

但是我不明白为什么会失败.其他线程是否无法访问"实际"停止变量?

Joh*_*int 6

JIT编译器可以在应用程序中重新排序读取和写入

  1. 这些行动是顺序一致的
  2. 更改的操作不会违反线程内语义.

这只是一种奇特的说法,所有操作看起来都应该像只由一个线程执行一样.所以你可以让JIT重新编译你的代码看起来像这样

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    if(!stop){
       while(true){

       }
    }
  }
Run Code Online (Sandbox Code Playgroud)

这是一种称为吊装的合法优化.它仍然与串行相同,但在使用多个线程时会提供令人惊讶的结果.

通过声明字段volatile,您告诉Java不要执行任何重新排序.与Nathan Hughes提到的记忆一致性一起


Nat*_*hes 5

实例变量stop需要是volatile,否则无法保证其他线程会看到对它的更改.工作中存在许多相互冲突的兴趣:线程需要一致的程序状态视图,CPU希望能够缓存数据,JVM希望能够重新排序指令.使实例变量变为volatile意味着它不能被缓存,并且在建立限制指令重新排序的关系之前发生.

请参阅此其他答案(+1),以获得在不标记变量volatile的情况下可能发生重新排序的良好示例.

(顺便说一下,使用中断进行线程取消比使用实例变量更好.)