2011-11-16 5 views
2

ThreadPoolExecutorでRunnableを実行し、このRunnableが共有状態を変更した場合、共有状態への変更が元のスレッドに表示されるかどうかは保証されますか?実行ファイルをプールに提出したのは?共有状態に1つのライターと1つのリーダーしかないと仮定します。 Futureを返すExecutorServiceを使用すると、Future.get()を実行すると可視性が保証されます。ThreadPoolExecutor.execute()でメモリの可視性を保証

それが依存

class State { 
    private int x; 
    public State(int y) { x = y; } 
    public void setX(int y) { x = y; } 
    public int getX() { return x; } 
} 

main() { 
    threadPool = new ThreadPoolExecutor(8, 16, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(...)) 

    final State myState = new State(1); 

    threadPool.execute(new Runnable() { 
     public void run() { 
      myState.setX(50); 
     } 
    }); 

    while (true) { 
     if (myState.getX() == 50) { 
      break; 
     } 
     sleep(); 
    } // would this loop terminate? 
} 

答えて

5

は、元のスレッドが更新されることはありませんxの値のキャッシュされたコピーを持っていることが主な理由は、状態の変更はすぐに元のスレッドに反映されるという暗黙の保証はありません別のスレッドはメインメモリのxの値を変更します。

あなたが好き、volatileキーワードを使用して明示的な保証を追加することでこの問題を回避することができます。これは、それがxの値をキャッシュすることはできませんコンパイラに指示し、毎回プログラムがxそれを読み込むこと

class State { 
    private volatile int x; 
    public State(int y) { x = y; } 
    public void setX(int y) { x = y; } 
    public int getX() { return x; } 
} 

メインメモリにある値をチェックする必要があります。これにより、元のスレッドは他のスレッドがそれを変更するとすぐに新しい値xを表示します。ここ

詳細:かなり多くの

http://www.javamex.com/tutorials/synchronization_volatile.shtml

1

スレッドは、メモリの同期ビューを保証します(1つの変数のみがいることを同期するvolatile以外の)その仕事を終えたことを検出するための任意の健全な方法。あなたの例は、スレッドが終了したことを確認する方法がないので、明らかに動作しません。 C#では特定の適時性が保証されていないため、sleepをシンクロナイズの形式として使用することはできません。

+0

ありがとうございます - これは私にとって理にかなっています。上記の私の例は実際には少し工夫されています。私が見た元のコードは、実際にはスレッドプールに非同期タスクの束をキックオフします。これらのタスクは、潜在的に一部の状態を更新する可能メインスレッドはちょうどタイトなループで状態をポーリングし、いくつかの作業を行います。タスクが完了するまで明示的に待つ必要はありません。これを反映するためにコードサンプルを編集します。 – Harish

+0

シグネチャデバイスは、ある種の正常なスレッド間シグナリングデバイス(イベントのようなもの)を通して状態をポーリングすると、スレッドXがスレッドYのイベント/シグナルを参照すると、送信前にスレッドXが行ったメモリ変更を確認する可能性が高くなります信号または事象。偽装しないでください - 適切なシグナリング/同期デバイスを使用してください。 –