在《Effective Java》中,作者提到了
while (!done) i++;
可以通过 HotSpot 优化成
if (!done) {
while (true) i++;
}
我对此感到非常困惑。该变量done
通常不是const,为什么编译器可以这样优化?
在《Effective Java》中,作者提到了
while (!done) i++;
可以通过 HotSpot 优化成
if (!done) {
while (true) i++;
}
我对此感到非常困惑。该变量done
通常不是const,为什么编译器可以这样优化?
作者假设该变量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();
}
与提升无关的其他优化也适用于此。
希望有帮助。
Joshua Bloch 的“Effective Java”解释了为什么在线程之间共享变量时必须小心。如果在线程之间的关系之前不存在任何显式发生,则允许 HotSpot 编译器出于速度原因优化代码,如dmide所示。
现在大多数微处理器都提供不同种类的乱序策略。这导致了弱一致性模型,这也是 Java 平台内存模型的基础。背后的想法是,只要程序员没有明确表达对线程间协调的需求,处理器和编译器就可以进行不同的优化。
两个关键字volatile
(原子性&可见性)和synchronized
(原子性&可见性&互斥)用于表达更改的可见性(对于其他线程)。但是,除此之外,您还必须知道发生前发生的规则(参见 Goetz 等人的“Java Concurrency in Practice”第 341f 页 (JCP) 和 Java 语言规范 §17)。
那么,当System.out.println()
被调用时会发生什么?见上文。首先,你需要两个System.out.println()
电话。一个在 main 方法中(更改后done
),一个在启动的线程中(在while
循环中)。现在,我们必须考虑 JLS §17 中的程序顺序规则和监视器锁定规则。这里是简短的版本:您有一个公共锁对象 M。在 A解锁M之前,线程 A 中发生的所有事情在B锁定M的那一刻对另一个线程 B 可见(参见 JCP)。
在我们的例子中,两个线程PrintStream
在System.out
. 当我们查看内部println()
时,您会看到调用synchronized(this)
.
结论:两个线程共享一个共同的锁 M,它被锁定和解锁。System.out.println()
“冲洗”变量的状态变化done
。
如果你System.out.println("i = " + i);
在while循环中添加。提升不起作用,这意味着程序按预期停止。println方法是线程安全的,jvm无法优化代码段?
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
关键字,这个程序就不能正常工作。
我认为当方法省略关键字时,这种变化会导致提升。synchronized