为什么这段代码会失败?

时间:2013-05-02 19:16:30

标签: java multithreading java-threads

在审核this question时,我注意到了这段代码:

class MyThread extends Thread {
  private boolean stop = false;

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

  public void setStop() {
    this.stop = true;
  }
}

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

4 个答案:

答案 0 :(得分:6)

只要

,JIT编译器就可以在应用程序中重新排序读取和写入
  1. 行动是顺序一致的
  2. 更改的操作不违反线程内语义。
  3. 这只是一种奇特的说法,所有操作看起来都应该像只由一个线程执行一样。所以你可以让JIT重新编译你的代码看起来像这样

    class MyThread extends Thread {
      private boolean stop = false;
    
      public void run() {
        if(!stop){
           while(true){
    
           }
        }
      }
    

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

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

答案 1 :(得分:5)

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

请参阅this other answer(+1),了解在不标记变量volatile的情况下可能发生重新排序的一个很好的例子。

(顺便说一句using interruption for thread cancellation比使用实例变量更好。)

答案 2 :(得分:1)

变量stop必须声明为volatile。

虽然我更喜欢使用中断来停止线程。

答案 3 :(得分:0)

其他线程无法保证看到更新的stop值 - 您需要建立“之前发生”关系。最简单的方法是停止挥发。