2009-07-15 11 views
20

あるスレッドが配列の1つのインデックスから読み取るときに並行性の問題がありますか?インデックスが異なる限り、別のスレッドが配列の別のインデックスに書き込みますか?java配列のスレッドセーフ

class Test1 
{ 
    static final private int N = 4096; 
    final private int[] x = new int[N]; 
    final private AtomicInteger nwritten = new AtomicInteger(0); 
    // invariant: 
    // all values x[i] where 0 <= i < nwritten.get() are immutable 

    // read() is not synchronized since we want it to be fast 
    int read(int index) { 
     if (index >= nwritten.get()) 
      throw new IllegalArgumentException(); 
     return x[index]; 
    } 
    // write() is synchronized to handle multiple writers 
    // (using compare-and-set techniques to avoid blocking algorithms 
    // is nontrivial) 
    synchronized void write(int x_i) { 
     int index = nwriting.get(); 
     if (index >= N) 
      throw SomeExceptionThatIndicatesArrayIsFull(); 
     x[index] = x_i; 
     // from this point forward, x[index] is fixed in stone 
     nwriting.set(index+1); 
    }  
} 

編集(この例では、必ずしも唯一の私のポイントを説明するために、実際の使用はお勧めしません):この例を批判は私の質問はありませんが、私は文字通り、同時にに、一つの指標にあれば配列アクセスを知りたいです他の索引へのアクセスは、並行性の問題を引き起こし、単純な例を考えることができませんでした。

答えて

12

あなたは配列を変更することで、無効な状態を得ることはありませんが2つのスレッドが同期なしで非揮発性の整数を表示しているときと同じ問題が発生します(Memory Consistency ErrorsのJavaチュートリアルのセクションを参照してください)。基本的に問題は、スレッド1がスペースiに値を書き込む可能性がありますが、スレッド2が変更を認識するとき(または、そうでない場合)は保証されません。

クラスjava.util.concurrent.atomic.AtomicIntegerArrayは、あなたがしたいことを行います。

+0

ありがとう... drat、私はバイト[]配列を使いたいと思います。 ....私はちょうど同期メソッドを使用し、それを簡単に保つと思います。 –

+2

書き込みよりも読み込み量が多い場合は、java.util.concurrent.locks.ReadWriteLockを参照してください。 –

+0

興味深い... –

4

このサンプルには、散文の質問とは異なるたくさんのものがあります。

この質問に対する答えは、配列の別個の要素が独立してアクセスされるため、2つのスレッドが異なる要素を変更する場合に同期化する必要はありません。

しかし、Javaメモリモデルでは、アクセスを同期させない限り、あるスレッドによって書き込まれた値が別のスレッドに見えるという保証はありません。

あなたが実際に達成しようとしていることに応じて、java.util.concurrentにはすでにあなたのためのクラスがあります。また、そうでなければ、あなたのコードはハッシュテーブルを管理するのと同じことをしているように見えるので、ConcurrentHashMapのソースコードを見てみることをお勧めします。

1

writeメソッドのみを同期させるかどうかはわかりませんが、readメソッドを非同期にすると機能しません。すべての結果ではありませんが、少なくともwriteによってオーバーライドされた値を返す方法はreadになる可能性があります。

1

はい、マルチCPU /コア環境でもキャッシュのインターリーブが正しく行われない可能性があります。それを避けるために、いくつかのオプションがあります:

  • 使用アトミック配列内の要素を設定(またはjsr166y追加された機能
  • 使用AtomicXYZ []配列
  • 使用カスタムJava7中に危険な日、プライベートライブラリ1つの揮発性のフィールドを持つオブジェクトとそのオブジェクトの配列を持っている。
  • 使用jsr166yの補遺のParallelArrayを代わりにあなたのアルゴリズムで
1

読み取り()が同期されていないので、次のSCENを持つことができますアリオ:

Thread A enters write() method 
Thread A writes to nwriting = 0; 
Thread B reads from nwriting =0; 
Thread A increments nwriting. nwriting=1 
Thread A exits write(); 

あなたは、のようなものについて何を(配列インデックスの問題を割り引く)あなたの変数のアドレスは決して競合していることを保証したいので:

​​3210
+0

ありがとうございます、私の質問ではありません&あなたのシナリオは起こりません(ステップ2と3は決して発生しません) –