2017-05-25 5 views
3

私はJavaでマルチスレッドを学んでいましたが、このチュートリアルでは、同期を取り除くとバグが発生してしまったとのことでしたので、試してみたところでSystem.out.println(Thread.currentThread().getName() + " " +count); を試していました。プログラムはうまくいきました。しかし、同期された単語だけが削除され、印刷行(System.out.println(Thread.currentThread().getName() + " " +count);)が追加されない場合、プログラムはバグが予想されます。System.out.println(Thread.currentThread()。getName()+ "" + count)を使用します。同期につながる

私は、印刷行を追加すると、それは同期させることができる方法を理解することはできません。複数のスレッドが同時にで同じフィールドへのアクセスを試みると、

public class intro implements Runnable { 

    int n=10000; 
    private int count = 0; 

    public int getCount() { return count; } 

    public synchronized void incrSync() { count++; } 

    public void run() { 
     for (int i=0; i<n; i++) { 
      incrSync(); 
      //System.out.println(Thread.currentThread().getName() + " " +count);  
     } 
     } 


    public static void main(String [] args) { 

     intro mtc = new intro(); 
     Thread t1 = new Thread(mtc); 
     Thread t2 = new Thread(mtc); 
     t1.start(); 
     t2.start(); 
     try { 
      t1.join(); 

      t2.join(); 

     } catch (InterruptedException ie) { 
     System.out.println(ie); 
     ie.printStackTrace(); 
    } 
    System.out.println("count = "+ mtc.getCount()); 
} 
} 
+3

println()が同期しています。そのため、スレッドはロックを取得して解放します。もちろん、コードをスレッドセーフにするためには、それに頼るべきではありません。 –

+0

@JBNizet私はそれへの参照を見つけることができません、あなたは1つを提供してくださいできますか?私はJavaのドキュメントとhttps://stackoverflow.com/a/9459886を確認しました。 – 11thdimension

+0

javadocはメソッド(またはその内部コード)が同期しているかどうかは言及していません。これは実装の詳細です。これはAPIの一部ではありません。しかし、PrintStreamのソースコードはJDKに付属しています。ただそれを見てください。 –

答えて

0

printlnメソッドは、newlineを呼び出します。これは​​ブロックのメソッドです。それはスレッドセーフではありませんが、正しい結果を与えています。

は、T1は、カウント5を読み、T2は、競合状態が起こり、その後、同時に5カウント読み考えてみましょう。ブロックしているSystem.out.println(Thread.currentThread().getName() + " " +count);を使用しているため、正しい結果が得られています。スレッド番号を増やします。

private void newLine() { 
    try { 
     synchronized (this) { 
      ensureOpen(); 
      textOut.newLine(); 
      textOut.flushBuffer(); 
      charOut.flushBuffer(); 
      if (autoFlush) 
       out.flush(); 
     } 
    } 
    catch (InterruptedIOException x) { 
     Thread.currentThread().interrupt(); 
    } 
    catch (IOException x) { 
     trouble = true; 
    } 
} 
+0

がシンクロしていますが、 'n'を大きくすると(1000000など)、それでも正しい数を集計しません(1999992) – herokingsley

2

同期の問題は、スレッド間で起こります。 run方法を印刷せずに

はほぼ連続的にカウンターにアクセスするタイトなループ内で座っています。複数のスレッドを同期化せずに行うと、障害が発生する可能性が非常に高くなります。印刷あなたはその時間印刷の(ほぼすべての)大半を過ごすためにループを変更し、たまにしかカウントを増加している追加することにより

。これは、競合を引き起こす可能性がはるかに低いです。

コードはまだ印刷中にバグがありますが、唯一の違いは競合が起こりにくく、ちょうど1000ループのテストでは問題を示すのに十分ではないということです。スレッドが衝突する前に、おそらく数年間それを実行する必要があります。

これは、スレッド問題が見つけて修正するのは困難である理由の古典的なデモンストレーションです。そのループ(それはprintステートメントで)は何年も競合することなく複数のスレッド上で動くことができますが、スレッド間の衝突が1つしかないとコードが壊れます。心臓ペースメーカーや衛星や原子力発電所で起きたことを想像してみてください!

+1

'System.out.println'のいくつかの部分が同期化されているという事実も役立ちます。 –

+1

@MarkRotteveel - 確かにそうですが、発生する問題の**チャンス**をさらに減らすためだけです。 **問題を取り除きません**。 – OldCurmudgeon

+0

あなたの答えがそれに触れないので、私はただコメントしました。 –

関連する問題