为什么HotSpot会使用吊装优化以下内容?

时间:2012-02-18 03:12:18

标签: java jvm-hotspot

在“Effective Java”中,作者提到了

while (!done) i++;

可以通过HotSpot优化到

if (!done) {
    while (true) i++;
}


我很困惑。变量done通常不是 const ,为什么编译器可以这样优化?

4 个答案:

答案 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关键字时,此更改会导致提升