2012-01-07 12 views
3

私はJava Concurrency in Practiceを勉強していて、そこには、次のコードスニペットが悪い理由を説明しますジャワ、視認性と無限ループが発生

public class NoVisibility { 
    private static boolean ready; 
    private static int number; 
    private static class ReaderThread extends Thread { 

     public void run() { 
     while (!ready) { 
     Thread.yield(); 
     System.out.println(number); 
     } 
    } 

    public static void main(String[] args) { 
     new ReaderThread().start(); 
     number = 42; 
     ready = true; 
    } 
} 

このコードは、永遠に0またはループを印刷することができます。 NoVisibilityが(再注文問題のために)42の代わりに0を印刷できる理由を理解するのは簡単ですが、 私は無限ループについて少し混乱します。

このコードで無限ループが発生する可能性がある実際のシナリオは何ですか? readytrueに設定されている場合

+0

あなたがループを作る場合は、 'それが無限ループになってすることがはるかに可能性があり、{}ながら'私を発見しました。 (あなたは '{' btw)が見つからないようです –

+0

はい、申し訳ありません。ただ修正しました。これは一般的なカットアンドペーストエラーでした。 :) –

答えて

8

ループが停止します。 readyは、メインスレッドによってtrueに設定されています。しかし、readyフィールドはvolatileではないので、ループしているスレッドは、引き続きキャッシュされた値:falseを見るかもしれません。

volatileキーワードは、揮発性のフィールドを読んで、すべてのスレッドが実際に他のスレッドによってこのフィールドに格納された最後の値を表示することを保証します。 volatileがなければ、この保証はありません。あなたはサイクルで印刷するように、あなたが出力ストリームに同期させ、それがすべてのメモリフェンスを必要とするので、あなたは終了し、実際には以下となります。

+0

ありがとう、あなたは私にそれを説明したのでかなり明らかにそうだ:) –

0

まあ、それは物事は​​ほぼその容易ではないことが判明します。

このような動作には依存してはいけませんが、問題を説明する場合は特に注意してください。多くのシステムコール、特にI/Oでは、トリック。だからあなたは "baaaaadだ"と言ってしまい、それを証明することができず、ちょっとイライラしています。

コード例については、illustrating volatile : is this code thread-safe?をチェックしてください(恥知らずのプラグインで申し訳ありませんが、私はこのコードしかありません)。

0

次のコードを参照してください。これは、x86のInfiniteループをかなり紹介しています。 はjdk8で試してみました

package com.snippets; 


public class SharedVariable { 

    private static int sharedVariable = 0;// declare as volatile to make it work 
    public static void main(String[] args) throws InterruptedException { 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       sharedVariable = 1; 
      } 
     }).start(); 

     for(int i=0;i<1000;i++) { 
      for(;;) { 
       if(sharedVariable == 1) { 
        break; 
       } 
      } 
     } 
     System.out.println("Value of SharedVariable : " + sharedVariable); 
    } 

} 

トリックは、プロセッサが並べ替えではなく、視認性のバグを紹介し、いくつかの最適化を行うために コンパイラを作る行うことを期待するのではありませんJDK7。

上記のコードを実行すると、更新された値sharedVariableが決して見られないので、無期限にハングすることがわかります。

コードを修正するには、sharedVariableをvolatileとして宣言します。

通常の変数が機能せず、上記のプログラムがハングするのはなぜですか?

  1. sharedVariableはvolatileとして宣言されていません。
  2. sharedVariableはvolatileコンパイラとして宣言されていないため、コードを最適化します。 それは、sharedVariableが変更されないように見えるので、私はいつもループ内でメモリから を読み込む必要があります。それはループからsharedVariableを取り去ります。以下のようなもの。githubので共有

    for(int i=0i<1000;i++)/**compiler reorders sharedVariable 
    as it is not declared as volatile 
    and takes out the if condition out of the loop 
    which is valid as compiler figures out that it not gonna 
    change sharedVariable is not going change **/ 
        if(sharedVariable != 1) { 
        for(;;) {} 
        }  
    } 
    

:(!レディ)https://github.com/lazysun/concurrency/blob/master/Concurrency/src/com/snippets/SharedVariable.java

関連する問題