23

「Effective Java」で、著者は次のように述べています。

while (!done) i++;

HotSpotによって最適化できます

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


私はそれについて非常に混乱しています。変数doneは通常constではありません。コンパイラがそのように最適化できるのはなぜですか?

4

4 に答える 4

29

作成者は、変数がローカル変数であると想定しています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();
}

ここでは、巻き上げとは関係のない他の最適化も適用されます。

お役に立てば幸いです。

于 2012-02-18T03:38:55.647 に答える
0
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

于 2016-10-08T07:26:08.450 に答える
0

System.out.println("i = " + i);while ループを追加する場合。巻き上げは機能しません。つまり、プログラムは期待どおりに停止します。jvmがコードセグメントを最適化できないように、printlnメソッドはスレッドセーフですか?

于 2012-02-20T08:42:28.017 に答える