【问题标题】:Java: For loop in while loop not running unless println statement includedJava:除非包含 println 语句,否则循环中的 For 循环不会运行
【发布时间】:2020-12-30 11:01:11
【问题描述】:

我正在尝试在无限 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"); //If this isn't included, 
                                        //the exit statement isn't executed
      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;
  }
}

这只是从一个更大的循环中提取的一个小例子。我该如何解决这个问题?

【问题讨论】:

    标签: java multithreading loops


    【解决方案1】:

    你有一个数据竞赛。其中一个线程写入varint,另一个线程读取varint,没有显式同步。 varint 未声明为易失性。根据 Java 内存模型,不能保证读取线程会看到 varint 已更改。

    当您添加 println 时它会起作用,因为 println 在内部使用同步,这使得 varint 对正在运行的线程可见。

    要么使用锁定来读/写varint,要么声明它volatile

    这是 Java 内存模型和 volatile 的一个很好的来源:

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

    【讨论】:

    • 我从未听说过 volatile 关键字。它到底有什么作用?
    • 它做了一些事情:对该变量的读/写包括内存屏障。它还告诉编译器另一个线程可以修改它,因此对 volatile 变量的访问没有优化为使用临时或寄存器。
    • 您能否再解释一下,或者提供一个链接,Java 内存模型中的原因是什么?
    • @JoshuaD,我添加了答案的链接。
    【解决方案2】:

    不保证在此头像中执行循环的主线程看到varint 的任何更新。所以varint 可以更新为 1 或 100,但仍然不能保证主线程能够看到更新。

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

    see the following link 来自 Java 5 并发架构师。本文解释:“状态标志和易失性”

    另一方面,在某些情况下(如您添加打印时的情况那样间歇性地)读取线程可能会看到更新,并且看起来程序运行正常。如果将此类可见性问题投入生产,则极难跟踪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多