为什么这段代码可能会失败?

34 浏览
0 Comments

为什么这段代码可能会失败?

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

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

然而,我不明白为什么会失败。其他线程无法访问到“实际”的stop变量吗?

0
0 Comments

为什么这段代码可能会失败?

这段代码中的实例变量`stop`需要被声明为`volatile`,否则不能保证其他线程能够看到对其的修改。在这里存在许多相互冲突的利益:线程需要对程序状态有一致的视图,CPU需要能够缓存数据,JVM需要能够重新排序指令。将实例变量声明为`volatile`意味着它不能被缓存,并且建立了happens-before关系以限制指令重新排序。

请参阅这个问题的其他回答,其中有一个很好的例子,展示了在没有将变量声明为`volatile`时可能发生的重新排序。

(顺便说一下,使用中断来取消线程比使用实例变量更可取。)

你应该提到hoisting,这是导致这段代码可能失败的主要原因。我创建了自己的回答来解决hoisting。

:这和指令重新排序有什么不同吗?

你是对的,它们是不同的。我猜你提到的具体类型的重新排序并不明显。尽管你确实提到了它,但你的论证似乎更多地集中在内存可见性上,而不是重新排序。

0
0 Comments

为什么这段代码可能会失败?

这段代码可能会失败的原因是变量"stop"没有被声明为volatile。虽然我更喜欢使用中断来停止线程。

解决这个问题的方法是将变量"stop"声明为volatile。这样做可以确保当"stop"变量的值发生变化时,所有线程都能够立即看到这个变化。如果不将变量声明为volatile,可能会导致线程无法正确地检测到"stop"变量的变化,从而无法正确地停止线程。

以下是将变量"stop"声明为volatile的示例代码:

volatile boolean stop;

通过将变量"stop"声明为volatile,可以确保在一个线程中改变"stop"变量的值后,其他线程能够立即看到这个变化。这样就能够正确地停止线程,避免可能的失败。

0
0 Comments

为什么这段代码会失败?

这段代码可能会失败的原因是JIT编译器可以重新排列应用程序中的读写操作,前提是这些操作是顺序一致的,并且修改后的操作不会违反线程内部的语义。换句话说,所有操作应该看起来就像是由单个线程执行一样。因此,JIT编译器可以重新编译代码,使其看起来像这样:

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

这是一种合法的优化,称为hoisting。它在行为上与串行代码相同,但在使用多个线程时会产生意想不到的结果。

解决这个问题的方法是通过声明一个volatile字段来告诉Java不要执行任何重新排序。同时,内存一致性也是一个重要因素。

JVM会检查doSomeWork()方法是否在hoisting之前设置了stop字段吗?我认为是的,否则这个优化就不那么理想了。

是的,绝对会!否则,这将导致一种糟糕的优化结果。

0