2016-08-06 7 views
1

こんにちは、私は、コードの下に実行しようとしていますし、出力で混乱してスレッドのJavaでの出力を期待取得するにはB:7は静的VAR

静的な値が8に変更された後、Bスレッドが実行されてその値7を印刷しようとしている可能性があります。私は意味する私は静的変数ですし、それのコピーは1つだけです。 i++ 3などの異なる操作の

public class ThreadStaticTest implements Runnable { 

    static int i = 5; 

    public static void main(String[] args) { 
     ThreadStaticTest obj = new ThreadStaticTest(); 
     Thread t1 = new Thread(obj); 
     Thread t2 = new Thread(obj); 
     Thread t3 = new Thread(obj); 

     t1.setName("A"); 
     t2.setName("B"); 
     t3.setName("C"); 

     t1.start(); 
     t2.start(); 
     t3.start(); 
    } 

    @Override 
    public void run() { 
     i++; 
     System.out.println(Thread.currentThread().getName()+" : "+i); 
    } 
} 
+0

「i」のコピーは1つだけだと思いますか? 'i ++'は 'i'をコピーし、インクリメントして書き戻します。これはアトミックな操作ではありません。 – dhke

+1

また、スレッドAはiを7と読み、印刷する文字列を生成し、スレッドBはそれをインクリメントして8を出力し、スレッドAはその文字列を出力することができる。 –

+0

@dhke:ここでの実行は )Aが実行を開始した> i ++>インクリメントされた値が6になるように到達しました。 2)Bが実行を開始しました> i ++をインクリメントして7に設定しました。 3)A値を出力7 4) i ++>値を8に増やして>値8を印刷します。 5)今度はBの印刷開始値がまだ7です! –

答えて

2

思う:

  1. スタックのスタック
  2. ストアトップのi(JVMがスタックに、JVMはスタックマシンである)
  3. 増分トップフェッチ変数iに戻ってください。

確かに、OpenJDKの8のjavacはにrun()メソッドをコンパイルします。つまり、それは再使用することができ、iは揮発性ではないため、JVMは、読み取りアクセスを最適化することが許可され、

さらに
public void run(); 
    Code: 
     0: getstatic  #11     // Field i:I 
     3: iconst_1 
     4: iadd 
     5: putstatic  #11     // Field i:I 

println()コールのスタックにすでにある値を返します。したがって、println()呼び出しでは、通常、ストアされた値ではなく、現在のスレッドの観点からの値が表示されます。また、バイトコードが複数のレジスタにアクセスできるネイティブコードにコンパイルされていると、状況は「悪化」する可能性があります。

ありは、バイトコードでprintln()getstatic呼び出しですが、それnoted-- --asはおそらく離れて最適化されます。とにかく、それによってどのような価値が読み取られるという保証はありません。表示される値が同じスレッドが以前に見た値であることを確認することさえできません。

次に、i = 6と仮定して、次の操作順序を考えてみましょう。

  1. スレッドAは:i
  2. スレッドCをフェッチ:インクリメントi
  3. スレッドA:店舗i
  4. スレッドB:インクリメント:i
  5. スレッドBを取り出しi
  6. スレッドAをフェッチi
  7. スレッドB:店舗i
  8. スレッドC:刻みi
  9. スレッドC:店舗i

我々は何を得るのですか?

  • Aは6を取り出し、格納7、おそらく7を印刷します。
  • Bは7をフェッチし、8を格納します。おそらく8を出力します。
  • Cは6をフェッチし、7を格納するとおそらく7が出力されます。

この実行順序を保証するものがないため、実行ごとに異なる結果が得られるはずです。

+0

はいこれも可能です! :)ので、スレッドケースでは、Javaを信頼しないでください:Dも単一のステートメント!私たちは同期や何が必要です! –

+1

@AmbitionFollwerそれだけでなく、[原子変数](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html)もかなりありましたしばらく、今。 – dhke

+0

AtomicIntegerのgetAndIncrement()APIを試しましたが、運はありません!彼らは内部的に揮発性を使用して、私はすでにその試みた。それでも私たちは時々o/pより上になることができます –