2012-02-18 4 views

答えて

20

変数doneはローカル変数であると仮定していますが、Javaメモリモデルでは同期プリミティブなしで他のスレッドにその値を公開する必要はありません。または、別の言い方をすれば、doneの値は、ここに示されている以外のコードでは変更または表示されません。

この場合、ループはdoneの値を変更しないので、その値を効果的に無視することができ、コンパイラはその変数の評価をループ外に持ち上げて、 "ループの一部。これにより、作業が少なくて済むため、ループが高速に実行されます。

これは、そのような配列の長さとして、あまりにも複雑な式で動作します。この場合

int[] array = new int[10000]; 
for (int i = 0; i < array.length; ++i) { 
    array[i] = Random.nextInt(); 
} 

、素朴な実装は、配列万倍の長さを評価するだろうが、変数の配列があるので、割り当てられたことがないと、配列の長さが変化することはありません、評価がに変更することができます。

int[] array = new int[10000]; 
for (int i = 0, $l = array.length; i < $l; ++i) { 
    array[i] = Random.nextInt(); 
} 

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

希望に役立ちます。

+0

私はそれを得ることはできません、条件が常にtrueの場合、どのようにループが終了するのですか? –

+2

私はEJのポイントの著者は、JITコンパイラ*がこのように最適化できるので、プログラマは別のスレッドから変更した 'done'の値に依存すべきではないということです。 JITコンパイラがこの構造体にコードを最適化し、ループが本当に決して終了しない可能性があります。 – ahawtho

+4

この最適化は、 'done'がインスタンス変数またはクラス変数であってもvolatileでない限り起こります。 – assylias

0

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

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(); 
} 
} 

上記のコードは、それがstopRequestedを飾るためにvolatileを使用等価である、有効コードの右あります。このメソッドは​​キーワードを省略した場合

private static boolean stopRequested() { 
    return stopRequested; 
} 

、このプログラムがうまく動作しません。
​​キーワードを省略した場合は、この変更により巻上げが発生すると思います。

関連する問題