在Java 8中是否存在并发中发生的活动失败

时间:2014-07-14 06:09:22

标签: java multithreading concurrency java-8

我将尝试重现以下有效Java(第二版)中提到的代码。 属于第10章并发项66。

public class StopThread {
   private static boolean stopRequested;

   public static void main(String args[]) {
      Thread backgroudThread = new Thread(new Runnable(){
             public void run() {
                int i = 0;
                while(!stopRequested) {
                       i ++;
                }
             }
      });
      backgroudThread.start();

      TimeUnit.SECONDS.sleep(1);
      stopRequested = true;
   }
}

根据作者的描述,当您运行上述过程段时,backgroupdThread将不会终止。但是我无法在设置Java8环境的机器中重现它。那么这个问题是否已在Java最新版本中进行了优化?

已更新
我在linux操作系统(redhat)中再试一次。它总是不会终止。之前我在Win7操作系统COREi5中运行它。它总是终止。

PS:在linux操作系统(redhat)中。如果按上述代码运行,程序将不会终止。但是,如果我添加" System.out.println(i)"在" i ++"之后在"而"环。此时。程序将始终终止。这是我的新发现。如果您知道原因,请发布您的答案。我将继续深入研究这些系列问题,直到找到真正的原因。

4 个答案:

答案 0 :(得分:3)

嗯,如果要更准确,作者写道:

  

然而,在我的机器上,程序永远不会终止:背景   线程永远循环!

现在你仍然可以争论这个原因他显然没有“永远”地运行这个程序但是你明白了。

顺便说一句,在我的机器上,程序永远不会终止(JDK 1.7.0_45)
顺便说一句2:如果我们希望它终止,我们所要做的就是将stopRequested声明为volatile

更新:
为了给没有这本书的人提供更多的上下文(并且真的应该得到它!),作者稍后会解释这个可能发生的原因是由于编译器检测到stopRequested未在本地更改,因此允许以下优化:

while(!stopRequested) {
      i ++;
}

变为:

if (!stopRequested)
    while(true) {
          i ++;
    }

JVM热点执行此类优化(称为提升)。如果你想深入研究为什么是一种合法的优化,你应该做一些阅读:JLS §17.4.3 Programs and Program Order

答案 1 :(得分:2)

不,作者说它永远不会终止在他的机器上。这完全是可能的,而且正是他试图做出的:应该同步对可变数据的共享访问,不仅要确保原子性,还要确保可见性

虽然分配给boolean是原子的,但后台线程可能主线程更改为stopRequested。< / p>

作者还提出了一个简单的解决方法:将stopRequested声明为volatile

答案 2 :(得分:1)

  

根据作者的描述,当您运行上述过程段时,backgroundThread将不会终止。

我没有把这本书放在我面前,但我强烈怀疑这不是那么说的。

我认为它实际上说的是背景线程可能不会终止。单词&#34;不会&#34;和&#34;可能不会&#34;意思不同......

更新 - 请参阅@ alfasin对Bloch实际编写内容的回答。


  

但我无法在设置Java8环境的机器中重现它。那么这个问题是否已在Java最新版本中进行了优化?

没有。没有&#34;优化&#34;。与众不同。

实际上,该程序已经误入了Java语言规范所指出的行为未指定的区域。特别是,后台线程不会保证将看到主线程对该标志所做的更改。但它可能会看到它......取决于各种各样的东西。

您不能在Java 8上重现这一点并不奇怪。您可能也难以在较旧的Java平台上重现它。从某种意义上说,正是这种困难&#34;这就是这类问题如此粗糙的原因。

答案 3 :(得分:1)

  

此问题是否已在Java最新版本中进行了优化?

反过来说:这个&#34;问题&#34;精确存在 due 到Java Memory Model允许的优化。这些规定绝对没有从Java 8规范中删除,并且仍然存在。它们在多线程性能方面具有显着优势。

Java提供了特定的语言功能,使您的示例能够正常工作,但它并不强制在任何地方使用这些功能;它让程序员可以自行决定将它们与性能成本一起应用,只有在需要时才能应用它们。

仅供参考,我已经运行了您问题中的确切代码(加上缺少throws声明),并且该程序可靠地不会在我的OpenJDK 1.8上终止。