Java:除非包含println语句,否则for循环的while循环不会运行

时间:2020-09-11 22:50:00

标签: java multithreading loops

我正在尝试在无限while循环内运行for循环。没有打印语句时,代码未按预期运行,但有打印语句时,代码运行正常。这是代码:

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;
  }
}

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

2 个答案:

答案 0 :(得分:7)

您有一场数据竞赛。其中一个线程写入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

答案 1 :(得分:1)

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

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

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

另一方面,在某些情况下(如您添加打印件时的情况),读取线程可能会看到更新,并且似乎程序运行正常。这类可见性问题很难投入生产。