while 循环会在一段时间后停止执行吗?

Do while loops stop executing after a while?

所以我目前正在尝试使用多线程,因为我对 Java 还是很陌生。现在,我有多个线程都影响同一个 long 变量。然而,似乎过了一段时间除了检查 if 语句什么都不做,while 循环就停止执行了(就像它无限循环一样)。如果我只是在 while 循环中打印一些东西,它确实有效。

无效:

while(true){
  if(longVariable < 2)
    break;
}

是否有效:

while(true){
  System.out.println("hi");
  if(longVariable < 2)
    break;
}

这是为什么?

当你有一个不被线程更新的非易失性变量时,可以自由地内联它。

在您的第一种情况下,一旦 JIT 编译了代码,它可能不再读取值,而是使条件始终为真。

在第二种情况下,你有一个线程安全的操作。 printlnSystem.out 上是一个 synchronized 方法。这增加了读写屏障并防止 JIT 优化读取操作。

如果你试试这个,它应该也会起作用。

while(true){
  synchronized("hi") { } // does nothing but add memory barriers.
  if(longVariable < 2)
    break;
}

它还会使代码速度降低 1000 倍以上,因此在您尝试停止线程时该方法可能尚未 JIT。

简单的解决方案是使变量volatile每次都以线程安全的方式读取。

while(true){
  if(longVariable < 2)
    break;
}

在这段代码中,JVM 没有理由相信 longVariable 会永远改变。它可以有效地将其重写为:

long cached = longVariable;
while(true){
  if(cached < 2)
    break;
}

如果longVariable在执行时至少为2,则无限循环,因为没有什么可以改变cached

你必须给编译器一个提示,表明不允许重写。它与 JVM 上的 System.out.println 一起工作,因为它恰好是通过同步实现的(这很常见,但不是必需的)。这会插入内存屏障,这意味着 longVariable 的缓存值无效,必须再次读取。

但不能保证一定有效。为了使其正常工作,要么声明变量 volatile:

volatile long longVariable

这会阻止其值被缓存。

或者使用类似 AtomicLong 的东西来代替普通的 long 变量。

或者,最麻烦的是,使用显式同步(确保对变量的所有读取和写入都在同一个 "something" 上同步):

long v;
synchronized (something) {
  v = longVariable;
}
if (v < 2) ...