Java:如果语句在无限循环中

时间:2011-12-21 07:30:46

标签: java infinite-loop conditional-statements

我是Java的新手,以下内容可能很明显,但令我感到困惑。请考虑以下代码:

while(1>0){
  if(x!=0){
  //do something
  }
}

x变量在另一个线程中更改。但是,即使x不为零,也不会执行if语句中的代码。如果我通过以下

更改代码
while(1>0){
  System.out.println("here");

  if(x!=0){
  //do something
  }
}

当x不再为零时,现在执行if语句中的代码。我怀疑这与Java编译器的规则有关,但它对我来说非常混乱。任何澄清这一点的帮助将不胜感激。

5 个答案:

答案 0 :(得分:7)

如果x在另一个线程中发生变化,那么您可能会看到一个副作用,即您没有同步访问该变量。

Java内存和线程模型非常复杂,因此我建议您获取Brain Goetz的Java Concurrency in Practice副本并阅读。

简短的回答是确保x块中包含synchronized的访问权限:

while (1 > 0) {
    int temp;
    synchronized (this) {
        temp = x;
    }
    if (temp != 0) {
        // Do something
    }
}

同样在修改x

的代码中

请注意,此示例将x存储在临时变量中,因为您希望同步块尽可能小 - 它们会强制执行互斥锁定,因此您不希望在此处执行太多操作。

或者,您可以将x声明为volatile,这可能足以满足您的使用案例。我建议您使用synchronized版本,因为您最终需要知道如何正确使用synchronized,所以您现在也可以学习它。

答案 1 :(得分:2)

如果您使用的是多线程代码,请检查x变量是否为volatile。

答案 2 :(得分:1)

没有System.out.println("here");没有任何反应的原因,卡梅伦斯金纳的回答很好地解释了这一点。

那么为什么使用if(x!=0)println内的块会起作用? println执行synchronized阻止(请参阅PrintStream.write(String s))。这会强制当前线程从主内存中检索System.out状态并更新线程的缓存,然后让线程执行任何进一步的代码行。令人惊讶的副作用是,其他变量的状态(例如您的x)也会以这种方式更新,尽管x的锁定不涉及同步。它被称为搭载

如果我将使用自由文本来描述Java Memory Model Specification中描述的手续:据说在释放锁定之前执行的操作发生在操作之后执行操作获得锁定。

我将用一个例子来演示它。假设Thread 1已执行,并且只有在完成后才会启动Thread 2。还假设xyz是两个线程共享的变量。请注意,我们只能在z的{​​{1}}块内确定synchronized的值。

y

这当然是依赖于同步的非常糟糕的做法 ......

答案 3 :(得分:0)

这可能是编译器优化。它认识到,在while循环的范围内,变量永远不会改变,并且会缓存值而不是每次从内存中读取它。为了避免这种行为,简单地将变量声明为volatile:

private volatile int x;

答案 4 :(得分:0)

还检查你在if子句中做了什么。它们只是内存操作,它比写入控制台快得多,所以在更改状态之前,你在最后一种情况下执行更多的操作。