Java:只有在包含println语句时,才会执行while循环中的for循环。

huangapple go评论78阅读模式
英文:

Java: For loop in while loop not running unless println statement included

问题

以下是翻译好的部分:

我正在尝试在一个无限的while循环内部运行一个for循环。当没有print语句时,代码不会按预期运行,但是当有print语句时,它可以正常运行。以下是代码:

class Test implements Runnable{
  public static int varint = 0;
  public static void main(String args[]){
    Thread x = new Thread(new Test());
    int i;
    x.start();
    while(true){
      System.out.println("Hello World"); // 如果不包括这句话,
                                        // 就不会执行退出语句
      for(i=0;i<varint;i++){
        System.out.println("Exit");
        System.exit(0);
      }
    }
  }

  public void run(){
    try{
      Thread.sleep(5000);
    } catch(Exception e){
      System.out.println("Caught");
    }
    varint = 1;
  }
}

这只是从一个更大的循环中摘录的一个小例子。我该如何修复这个问题?

英文:

I am trying to run a for loop inside an infinite while loop. The code doesn't run as intended when there's no print statement, but when there is a print statement, it runs fine. Here is the code:

class Test implements Runnable{
  public static int varint = 0;
  public static void main(String args[]){
    Thread x = new Thread(new Test());
    int i;
    x.start();
    while(true){
      System.out.println(&quot;Hello World&quot;); //If this isn&#39;t included, 
                                        //the exit statement isn&#39;t executed
      for(i=0;i&lt;varint;i++){
        System.out.println(&quot;Exit&quot;);
        System.exit(0);
      }
    }
  }

  public void run(){
    try{
      Thread.sleep(5000);
    } catch(Exception e){
      System.out.println(&quot;Caught&quot;);
    }
    varint = 1;
  }
}

This is just a small example taken from a much bigger loop. How can I fix this?

答案1

得分: 7

你的代码存在数据竞争。其中一个线程写入了 varint,而另一个线程在没有明确同步的情况下读取了 varintvarint 没有声明为 volatile。根据Java内存模型,不能保证读取线程能够看到 varint 的变化。

当你添加了 println 后代码可以工作,因为 println 在内部使用了同步,这使得 varint 对运行中的线程可见。

要么使用锁来读写 varint,要么将其声明为 volatile

以下是关于Java内存模型和volatile的良好资源:

http://tutorials.jenkov.com/java-concurrency/java-memory-model.html#visibility-of-shared-objects

英文:

You have a data race. One of the threads write to varint and the other reads varint with no explicit synchronization. varint is not declared volatile. According to Java memory model, there is no guarantee the reading thread will ever see the that varint was changed.

It works when you add the println because println uses synchronization internally, which makes varint visible to the running thread.

Either use a locking to read/write varint, or declare it volatile.

This is a good source for the Java memory model and volatiles:

http://tutorials.jenkov.com/java-concurrency/java-memory-model.html#visibility-of-shared-objects

答案2

得分: 1

在这个仿真中执行循环的主线程不能保证看到对 varint 的任何更新。因此,varint 可能会被更新为 1 或 100,但主线程仍然无法保证能够看到这些更新。

为了保证内存可见性,请使用 volatile 或同步原语。

请参考来自 Java 5 并发架构师的以下链接。该文章解释了:“状态标志和 volatile”。

另一方面,在某些情况下(就像您的情况中添加打印时一样),读取线程可能会偶尔看到更新,并且程序似乎表现正常。如果此类可见性问题出现在生产环境中,追踪起来会非常困难。

英文:

The main thread executing the loop in this avatar is not guaranteed to see any updates to varint. So varint can be updated to 1 or 100 but there would still be no guarantees for main thread to be able to see the updates.

In order to guarantee memory visibility, use a volatile or synchronization primitives.

Please see the following link from an architect of Java 5 Concurrency. This article explains: "Status Flags and Volatile"

On the other hand, the reading thread in certain cases (intermittently as in your case when you add the print) might see the update and it might seem the program is behaving correctly. Such kind of visibility issues are extremely hard to track if it makes it to production.

huangapple
  • 本文由 发表于 2020年9月12日 06:50:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63855228.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定