2016-04-09 10 views
0

出力を見ると、メソッドを同期させるにもかかわらず、出力は順序付けられません。両方のスレッドがヒープ上の同じオブジェクト 'job'をインクリメントするので、どちらのスレッドが行を出力しても、結果は値が増えるはずです。しかし、なぜそれは無秩序な方法で印刷されていますか?Javaスレッドの混乱、なぜ出力が順序付けられていないのですか?

class TestSync implements Runnable{ 
    private int balance; 

    public void run(){ 
    for(int i=0; i<50; i++) { 
     increment(); 
    System.out.println("balance is "+balance); 
    } 
    } 
    public synchronized void increment(){ 
    balance++;  
    } 
} 


public class TestSyncTest { 

    public static void main(String[] args){ 
    TestSync job = new TestSync(); 
    Thread a = new Thread(job); 
    Thread b = new Thread(job); 
    a.start(); 
    b.start(); 
    } 
} 

出力:

balance is 2 
balance is 3 
balance is 4 
balance is 5 
balance is 6 
balance is 7 
balance is 8 
balance is 9 
balance is 10 
balance is 11 
balance is 12 
balance is 13 
balance is 14 
balance is 15 
balance is 16 
balance is 17 
balance is 18 
balance is 19 
balance is 20 
balance is 21 
balance is 22 
balance is 23 
balance is 24 
balance is 2 
balance is 25 
balance is 27 
balance is 28 
balance is 29 
balance is 26 
balance is 30 
balance is 32 
balance is 33 
balance is 34 
balance is 35 
balance is 36 
balance is 37 
balance is 31 
balance is 38 
balance is 40 
balance is 41 
balance is 42 
balance is 43 
balance is 44 
balance is 39 
balance is 46 
balance is 47 
balance is 45 
balance is 49 
balance is 48 
balance is 50 
balance is 52 
balance is 51 
balance is 53 
balance is 55 
balance is 54 
balance is 56 
balance is 58 
balance is 59 
balance is 60 
balance is 57 
balance is 61 
balance is 62 
balance is 63 
balance is 64 
balance is 65 
balance is 66 
balance is 67 
balance is 68 
balance is 69 
balance is 70 
balance is 71 
balance is 72 
balance is 73 
balance is 74 
balance is 75 
balance is 76 
balance is 77 
balance is 78 
balance is 79 
balance is 80 
balance is 81 
balance is 82 
balance is 83 
balance is 84 
balance is 85 
balance is 86 
balance is 87 
balance is 88 
balance is 89 
balance is 90 
balance is 91 
balance is 92 
balance is 93 
balance is 94 
balance is 95 
balance is 96 
balance is 97 
balance is 98 
balance is 99 
balance is 100 
+0

'synchronized'は注文を約束しません。これは、コードブロック上で異なるスレッドが実行している操作の可視性とアトミック性に関するものです。それが理由です。 – Tirath

+0

@Tirath [呼び出しが何を呼び出すかにかかわらず、時間的に重複しない呼び出しの相互順序を保持してメソッド呼び出しを正しく配置できる場合、実行は強く一貫しています。言い換えれば、メソッドが戻る前に、他のスレッドと一貫して完全に効果を発揮します。これは「線形性」または「糸の安全性」とも呼ばれます。](http://coldattic.info/shvedsky/pro/blogs/a-foo-walks-into-a-bar/posts/88)。私はこれがjavaの 'synchronized'がしているものだと思います。注文が保証されているかどうかにかかわらず、それがあなたが何を意味するかによって異なります。 –

答えて

2

同期されている唯一のものは、インクリメントです。印刷前の変数の読み込みは行われず、印刷自体は別のロックで同期されます。インクリメント

  • スレッド2:インクリメント
  • スレッド1:
  • を読み、印刷
  • スレッド2:だからあなたは

    • スレッド1を得ることができる
    • を読み、印刷

    をところで、バランスがありますすべて変数の値の読み込みを含むアクセスは、同じロックで同期する必要があります。

    変更のみ同期

    class TestSync implements Runnable{ 
        private int balance; 
    
        public void run(){ 
         for(int i = 0; i < 50; i++) { 
          incrementAndPrint(); 
         } 
        } 
    
        public synchronized void incrementAndPrint(){ 
         balance++;  
         System.out.println("balance is "+balance); 
        } 
    } 
    
  • +1

    printlnも同期されますが、同じロックを使用しません。 –

    +0

    したがって、ステートメントSystem.out.println( "balance is" + balance); 2つのステップで構成されています:1.バランスで値を読み取り、2.それを印刷します。 1つのスレッドは値を読み取った可能性がありますが、印刷前にフリーズされており、再び解放されると、フリーズされる前に読み取った値を出力します。そうですか? – Anudeep

    +0

    実際にはそれよりもはるかに原子ステップがあります:値を読み取り、値を文字列に連結します。それ自体は新しいhar配列を作成し、元の文字列のすべての文字を新しい配列にコピーし、整数を文字列に変換しますこれらのアトミックなステップのそれぞれの間で、スレッドはスケジューラによって別のスレッドを実行するために一時停止されることがあります。しかし、たとえ全体が単一のアトミック操作であったとしても、synchronizedブロックの外側で実行されているため、スレッド1が印刷される前にスレッド2をインクリメントすることができます。 –

    0

    へのコードブロックは、同期保護します。あなたのプログラムの周りに小さなスレッドを振りかけると、あなたが望むことができると想定するのはよくある間違いです。スレッドの安全性は操作のチェーンのようなもので、同期されていなければ、コードは任意の順序で実行できます。

    しかし、なぜそれは無秩序な方法で印刷されていますか?

    スレッドの目的は、独立したタスクを同時に実行することです。したがって、あるスレッドまたは他のスレッドが他のスレッドよりも速く実行される時間があることを期待する必要があります。

    本当の質問があります。どうしてそれは整然としているのですか?

    これは、あるスレッドが他のスレッドより先に開始することが原因と考えられます。 1つのスレッドが実行中で、もう1つがまだ起動していない場合、出力は「整然と」ですが、両方のスレッドが実行されると競合状態が確認できます。

    0

    あなたは2つのスレッドをカウンタで印刷していますが、アプリケーションが正常に動作しています。すべてのスレッドがカウンタ値を与えたいとすぐにコンソールに印刷されているのが分かります。フォーマットしたり

    すべてのスレッドに名前を追加し、データの起源を見ることができるように、あまりにも名前を印刷...どのスレッドから来ているもの値を識別するための方法...

    Thread a = new Thread(job, "t1"); 
    Thread b = new Thread(job, "t2"); 
    
    関連する問題