java指令の並び替えの問題について話します。


命令の並び替えは複雑で不思議な問題です。同じように例で始めます。

/**
 *        Happen-Before   .
 *          :a flag,      0 false. ThreadA     a=1,  flag=true.
 *         ,   ThreadB   if(flag)    ,   a=1, a=a*1  a   1,   if(a==0)       
 *  ,      .
 *       :   100        0         ,   1000      ,      .
 */
public class SimpleHappenBefore {
 /**             */
 private static int a=0;
 /**         */
 private static boolean flag=false;
 public static void main(String[] args) throws InterruptedException {
  //                   ,       
  for(int i=0;i<1000;i++){
   ThreadA threadA=new ThreadA();
   ThreadB threadB=new ThreadB();
   threadA.start();
   threadB.start();
   //         ,      ,              .
   threadA.join();
   threadB.join();
   a=0;
   flag=false;
  }
 }
 static class ThreadA extends Thread{
  public void run(){
  a=1;
  flag=true;
  }
 }
 static class ThreadB extends Thread{
  public void run(){
   if(flag){
   a=a*1;
   }
   if(a==0){
   System.out.println("ha,a==0");
   }
  }
 }
}
例は比較的簡単で、注釈も加えられています。詳しくは述べません。
命令の並び替えは何ですか?二つのレベルがあります
仮想マシンレベルでは、メモリの動作速度をCPUの動作速度よりも遅くするために、仮想マシンは、いくつかのルール(この規則は後で述べる)に従ってプログラムの作成順序を狂わせます。つまり、後のコードを時間順に先に実行します。前に書いたコードは後で実行します。CPUを最大限に利用します。上記の例を挙げると、a=1の操作ではなく、a=new byte[1024*1024](1 Mのスペースを割り当てます)`。明らかに、先にflags=trueを実行してCPUを使って、全体の効率を速めることができて、もちろんこのような前提は間違いが発生しないのです。ここでは二つのケースがありますが、後のコードは前のコードより先に実行します。前のコードは先に実行を開始しますが、効率が遅い場合、後のコードは実行を開始し、前のコードより先に実行が終了します。誰が先に始めても、とにかく後ろのコードはいくつかの場合、先に終了する可能性があります。
ハードウェアレベルでは、CPUは受信したコマンドの一部をルールに従って並べ替えます。同様にCPU速度がキャッシュ速度より速い原因に基づいています。前の目的と似ています。ハードウェア処理だけでは、毎回限られた命令範囲で並べ替えられます。ダミーマシンはより大きなレベルで、より多くの命令範囲で並べ替えられます。ハードウエアの並べ替えメカニズムは、「JVMからCPUメモリの命令を見て並べ替え」を参照してください。
並べ替えがよく分かりません。上ではそのシーンを簡単に紹介しただけです。この概念をよりよく理解するためには、いくつかの例とグラフを構築する必要があります。ここで紹介した二つの文章の中で、比較的に詳しく、生き生きとした文章「happens-before俗解」と「Javaメモリモード(二)を深く理解する――並べ替え」を紹介します。この中の「as-inf-serial」はマスターすべきもので、つまり、いくら並べ替えても、単スレッドプログラムの実行結果は変更されません。コンパイラ、実行時、プロセッサは「as-inf-serial」の意味を守らなければなりません。簡単な例をとって、

public void execute(){
 int a=0;
 int b=1;
 int c=a+b;
}
ここa=0、b=1の2つの句は勝手に並べ替えてもいいです。プログラムの論理結果に影響しません。しかし、c=a+bは前の2つの文の後に実行しなければなりません。
前の例から見れば、マルチスレッド環境で出現する確率はやはり高いです。キーワードにはvolatileとsynchronizedがあり、並べ替えを禁止できます。他にもいくつかの規則があります。これらの規則もあります。普段のプログラミング作業では並べ替えのデメリットを感じられません。
プログラム手順規則(Program Order Rule):一つのスレッド内でコード順に前に書いた操作が先に後ろに書いた動作になります。正確には、分岐、循環などの構造を考慮するため、コード順ではなくストリーム順序を制御するべきである。
モニタロックルール(Monitor Lock Rule):一つのロック操作は、先に同じオブジェクトに対して後ろからロックされるロック操作に発生します。ここでは同じロックを強調しますが、「後ろ」は他のスレッドで起こったロック操作のような時間的順序を指します。
volatile変数規則(Volatile Varable Rule):一つのvolatile変数に対する書き込み操作は、この変数に対する読み操作の後に発生します。ここでの「後ろ」も時間的な順序を指します。
スレッド起動規則(Thread Start Rule):Threadが独享するstart()方法はこのスレッドの各動作に先行します。
スレッド終了規則(Thread Termination Rule):スレッド内の各動作は、このスレッドの終了検出より先に発生しています。我々は、Thread.join()方法によって終了し、Thread.isAlive()の戻り値がスレッドの実行が終了したことを検出します。
スレッド中断規則(Thread Interruption Rule):スレッドinterrupte()メソッドへの呼び出しは、中断されたスレッドのコードよりも中断されたイベントの発生を検出し、スレッドが中断されているかどうかをThread.interrupted()方法で検出することができます。
オブジェクトの終端原則(Finalizer Rule):オブジェクトの初期化完了(構造関数実行終了)は、先にそのfinalize()メソッドの開始に発生します。
転送性(Transitivity):操作Aが操作Bに先行して発生し、操作Bが先に操作Cに発生した場合、操作Aが操作Cに先行して発生したという結論が得られる。
以上のような規則はhappen-beforeの順序を保証しています。以上の規則に合わないと、マルチスレッド環境では実行順序がコード順序と同じであることを保証できません。一つのスレッドで他のスレッドを観察すると、上記の規則に合致しないものは無秩序である」ということです。したがって、私たちのマルチスレッドプログラムがコード書き順に依存しているなら、上記の規則に適合しているかどうかを考慮して、該当しない場合はいくつかのメカニズムを通して該当させるべきです。
以上のような浅談java指令の並び替えの問題は、小編集が皆さんに提供した内容の全部です。参考にしてもらいたいです。どうぞよろしくお願いします。