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 编译了代码,它可能不再读取值,而是使条件始终为真。
在第二种情况下,你有一个线程安全的操作。 println
在 System.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) ...
所以我目前正在尝试使用多线程,因为我对 Java 还是很陌生。现在,我有多个线程都影响同一个 long 变量。然而,似乎过了一段时间除了检查 if 语句什么都不做,while 循环就停止执行了(就像它无限循环一样)。如果我只是在 while 循环中打印一些东西,它确实有效。
无效:
while(true){
if(longVariable < 2)
break;
}
是否有效:
while(true){
System.out.println("hi");
if(longVariable < 2)
break;
}
这是为什么?
当你有一个不被线程更新的非易失性变量时,可以自由地内联它。
在您的第一种情况下,一旦 JIT 编译了代码,它可能不再读取值,而是使条件始终为真。
在第二种情况下,你有一个线程安全的操作。 println
在 System.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) ...