「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();
}
ここでは、巻き上げとは関係のない他の最適化も適用されます。
お役に立てば幸いです。
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
System.out.println("i = " + i);
while ループを追加する場合。巻き上げは機能しません。つまり、プログラムは期待どおりに停止します。jvmがコードセグメントを最適化できないように、printlnメソッドはスレッドセーフですか?