在“Effective Java”中,作者提到了
while (!done) i++;
可以通过HotSpot优化到
if (!done) {
while (true) i++;
}
我很困惑。变量done
通常不是 const ,为什么编译器可以这样优化?
答案 0 :(得分:24)
作者假设变量done
是一个局部变量,它在Java内存模型中没有任何要求将其值暴露给没有同步原语的其他线程。或者换句话说:done
的值不会被任何代码更改或查看,除了此处显示的内容。
在这种情况下,由于循环不会更改done
的值,因此可以有效地忽略其值,并且编译器可以在循环外提升对该变量的求值,从而阻止它在循环的“热”部分。这使循环运行得更快,因为它必须做更少的工作。
这也适用于更复杂的表达式,例如数组的长度:
int[] array = new int[10000];
for (int i = 0; i < array.length; ++i) {
array[i] = Random.nextInt();
}
在这种情况下,天真的实现将评估数组的长度10,000次,但由于永远不会分配变量数组并且数组的长度永远不会改变,因此评估可以更改为:
int[] array = new int[10000];
for (int i = 0, $l = array.length; i < $l; ++i) {
array[i] = Random.nextInt();
}
此处的其他优化也适用于与吊装无关。
希望有所帮助。
答案 1 :(得分:2)
Joshua Bloch 的“Effective Java”解释了为什么在线程之间共享变量时必须小心。如果线程之间不存在任何明确的发生在关系之前,HotSpot 编译器可以出于速度原因优化代码,如 dmide 所示。
现在大多数微处理器都提供不同种类的乱序策略。这导致了弱一致性模型,它也是 Java 平台内存模型的基础。背后的想法是,只要程序员没有明确表达对线程间协调的需求,处理器和编译器就可以做不同的优化。
两个关键字volatile
(原子性&可见性)和synchronized
(原子性&可见性&互斥)用于表达变化的可见性(对于其他线程)。但是,此外,您必须知道发生在规则之前(参见 Goetz 等人的“Java 并发实践”p. 341f (JCP) 和 Java 语言规范 §17)。
那么,当调用 System.out.println()
时会发生什么?见above。
首先,您需要两个 System.out.println()
调用。一个在主方法中(在更改 done
之后)和一个在启动的线程中(在 while
循环中)。现在,我们必须考虑 JLS §17 中的程序顺序规则和监视器锁定规则。这是一个简短的版本:你有一个通用的锁对象 M。在 A 解锁 M 之前在线程 A 中发生的所有事情在 B 锁定的那一刻对另一个线程 B 是可见的M(见 JCP)。
在我们的例子中,两个线程在 PrintStream
中共享一个共同的 System.out
对象。当我们查看内部 println()
时,您会看到 synchronized(this)
的调用。
结论:两个线程共享一个公共锁M,它被锁定和解锁。 System.out.println()
“刷新”变量 done
的状态变化。
答案 2 :(得分:0)
如果在while循环中添加System.out.println("i = " + i);
。吊装不起作用,意味着程序按预期停止。 println方法是线程安全的,因此jvm无法优化代码段?
答案 3 :(得分:0)
# chmod 755 -R <path_to_your_webroot_folder>
# chown root:root -R <path_to_your_webroot_folder>
以上代码在有效代码中是正确的,相当于使用public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args)
throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested())
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
来装饰volatile
。
stopRequested
如果此方法省略了private static boolean stopRequested() {
return stopRequested;
}
关键字,则此程序运行不正常
我认为当该方法省略synchronized
关键字时,此更改会导致提升。