2016-03-24 6 views
1

私はインターネットで読み取ったいくつかの文書によれば、クラス原子の変数AtomicIntegerAtomicLongのように、... 1つのスレッドだけが同時にそれらにアクセスすることができます。しかし、AtomicBooleanでテストしようとしたときに、何かが間違っていました。例えばAtomicBooleanは "safe-thread"を保証しますか?

public class TestAtomicBoolean { 
    public static void main(String[] args) { 
     final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 

     new Thread("T1") { 
      @Override 
      public void run() { 
       while (true) { 
        System.out.println(Thread.currentThread().getName() + " is waiting for T3 set Atomic to true. Current is " + atomicBoolean.get()); 
        if (atomicBoolean.compareAndSet(true, false)) {       
         System.out.println("Done. Atomic now is " + atomicBoolean.get()); 
         break; 
        }      
       } 
      } 
     }.start(); 

     new Thread("T2") { 
      @Override 
      public void run() { 
       while(true) { 
        System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get());      
       }    
      }   
     }.start(); 

     new Thread("T3") { 
      @Override 
      public void run() { 
       System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get()); 
       System.out.println(Thread.currentThread().getName() + " is setting atomic to true"); 
       atomicBoolean.set(true); 
       System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get()); 
      }   
     }.start();     
    } 
} 

出力2ライン(*)で

T1 is waiting for T3 set Atomic to true. Current is false 
T1 is waiting for T3 set Atomic to true. Current is false 
T3 is setting atomic to true 
T2 false 
T3 true (*) 
T1 is waiting for T3 set Atomic to true. Current is false (*) 
T2 true 
Done. Atomic now is false 
T2 false 

、T3がtrueにAtomicBooleanを設定しているが、その後、T1の値がfalseであった読み出します。したがって、T1とT3は同時にAtomicBooleanにアクセスしますか? AtomicBooleanの仕組みを理解できません。

誰かが私を助けることができますか?

+0

@ElliottFrischもっと明確に説明できますか? : –

+0

コードで実行されるすべての操作が個別にスレッドセーフであっても、必ずしもスレッドセーフではありません。 –

答えて

2

AtomicBooleanは絶対確実でスレッドセーフです。

しかし、あなたの例では、アトミックブーリアンのこの原子的性質をテストしようとしています。System.out.printlnは、誤解を招くようなログを出力します。

だから我々はSystem.out.println()コードを見れば:

public void println(String x) { 
    synchronized (this) { 
     print(x); 
     newLine(); 
    } 
} 

我々は文脈で上記println()方法でのイベントの流れを見ることができます。

短い答え

スレッドT1プリント - T3を待っている>がtrueに原子力を設定します。現在の値はfalseです
スレッドT1のプリント - > T3がAtomicをTrueに設定するのを待っています。現在は偽です
スレッドT3プリント - > T3がアトミックを真に設定しています
スレッドT1 は、印刷するためにsysoutを呼び出します - > T3がアトミックをTrueに設定するのを待っています。 T3はtrueに原子力を設定するのを待っている> - > T3の印刷真
スレッドT1 SYSOUT完全と版画 - 現在は(ジャストSYSOUTメソッドと呼ばれるが、まだを取得していないロック)
スレッドT3プリントをfalseです。 Current is false

ログの順番は、T1が現在のatomicBooleanの値を読み取らないという印象を与えますが、これはSystem.out.printlnの実行中に発生する可能性のあるスレッドのインターリーブのためです。

詳細なシーケンス期待通りにアプリケーションが出力からatomicBoolean

final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 

ためfalseの初期値で初期の2つのログを開始し

がT1からであり、それはfalseとしてatomicBooleanの値を出力します。今のところ、2つのスレッドでもフローを見ることができるので、単純化するためにT2を無視します。

T3が実行を開始し、出力に示されているようにatomicBoolean~trueになります。

そして、上記の行を印刷した直後に、T1は実行の機会を得ます。この時点でatomicBooleanの値はfalseです。したがって、JVMは文字列T1 is waiting for T3 set Atomic to true. Current is falseを作成し、呼び出しについてはSystem.out.printlnメソッドを入力しましたが、まだsynchronized(this)ステートメントには達していないため、thisではまだロックが取得されません。それはT3が起こる可能性があり、この時点で

は実行を継続するためにそのターンを持って、trueatomicBooleanを行い、またSystem.out.println()すなわち、取得および解放(this上)ロックを使用して線T3 trueを印刷しています。

ここで、T1は前回の時点から実行を再開します。すなわち、System.out.printlnです。しかし、印刷しようとしているStringの値はすでに構築されており、その値はT1 is waiting for T3 set Atomic to true. Current is falseであることを覚えておいてください。だから今T1はこの行を印刷し続けます。

このフローを有効にすると、ログは観察したとおりになります。以下

T3 true 
T1 is waiting for T3 set Atomic to true. Current is false 

絵図

T1 & T3 w.r.t流れであり、(しようと)上記の議論を捕捉します。 は、スレッドが現在実行中であることを示します。スペースは、ターンを待っていることを示します。

1(false) 1(false)   1(false)just invoked 1(false)completed 
T1 -------------------   ------    ------------------ 
T3     ----------  ---------------- 
         2(false)  3(true) 

LEGEND: 
1(false) - printing of T1 is waiting for T3 set Atomic to true. Current is false 
2(false) - printing of T3 is setting atomic to true 
3(true) - printing of T3 true 
+0

ロギングフレームワークを使用するlog4j for multithreading http://logging.apache.org/log4j/2.x/ – mubeen

+0

@mubeenこのようなログがすでに存在しているか、私たちのコードで達成できるかどうかは確かではありません。 'sysout()'を内部的に呼び出す 'static synchronized'メソッドを持っていますが、私は気持ちがよく、上記の流れが発生する小さなウィンドウがほとんど見えます。 –

+0

ありがとう! –

0

よりもむしろ「いくつかのドキュメント」を参照して、あなたは、アトミックパッケージ内のクラスを考えるために迅速かつ簡単な方法は、取得するなど、各メソッドであるhttps://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html

で公式ドキュメントを読んしようとする場合がありますset、compareAndSetは、同期しているかのように動作します(遅延メソッドと弱メソッドを忘れる)。

+0

私はこの公式ドキュメントを読んだことがありますが、まだ理解していない:( "AtomicBoolean:原子的に更新可能なブール値。"私の例では、それは "アトミック"ではない:■2スレッドが同時にアクセスできる: –

関連する問題