1

長さ 100 の配列があります。マルチスレッド環境で使用する必要があります。配列にアクセスするスレッドは合計 10 あります。2 つのスレッドが同時に同じインデックスに書き込みを行う可能性がありますt1t2

Object[] data = new Object[100];

これを実装するための最良のアプローチは何ですか。

解決策 1 : 1 つのスレッドだけが配列に書き込むことができます。スレッドが異なるインデックスに書き込みたい場合でもt1、待つ必要があります。Collections.synchronizedList(....) を使用することも、t2使用することもできます。arrayList

  public class ThreadSafeArray(){
    private Object[] data = new Object[100];

    public synchronized Object getValueAtIndex(int index){
       return data[index]; // Removing index range check for simple explanation
    }

    public synchronized void setValueAtIndex(int index , Object value){
      data[index] = value; // Removing index range check for simple explanation

    }
  }

解決策 2 : 2 つの異なるスレッドが 2 つの異なるインデックスに同時に書き込むことができます。

        public class ThreadSafeArray(){
    private Object[] data = new Object[100];
    private Object[] lock = new Object[100];

    public Object getValueAtIndex(int index){
       synchronized(lock[index]) 
       {  
          return data[index]; // Removing index range check for simple explanation
       }
    }

    public void setValueAtIndex(int index , Object value){
       synchronized(lock[index]) 
      {
           data[index] = value; // Removing index range check for simple explanation
      } 
    }
  }

この要件を実装するためのより良い方法はありますか?

4

5 に答える 5

1

最初に、Java/C# であるかどうかにかかわらず、複数のスレッド間でデータを共有する場合にどのような問題が発生するかを確認する必要があることについて説明します。私たちが対処しなければならない問題は 3 つあります。

1. **Atomicity** of read/write operation on that datastructure
2. **Visibility** changes by one thread are visible to other thread.
3. **Reordering** - compiler n processor are free to reorder these instruction 
    as long as it maintains program order for single thread execution.

今あなたの問題について私が見ているのは. 固定サイズの配列があり、複数のスレッド間で共有していて、値を設定して取得しているだけであること。

まず、参照割り当てはアトミックであるため、以下のメソッドはアトミックです。スレッドセーフだとは言いません。まだ可視性が保証されていないためです。

public void setValueAtIndex(int index , Object value){
      data[index] = value; // Removing index range check for simple explanation
    }

可視性を保証するために、アプローチを変更できます (読み取りが書き込みよりも多い場合)

最初に配列を揮発性に宣言しましょう

volatile Object [] data = new Object[100];

これで、同期キーワードなしで get メソッドが正常に動作します

public Object getValueAtIndex(int index){
       return data[index]; // Removing index range check for simple explanation
}

上記のメソッドは、set メソッドに対してスレッドセーフになりました。配列をコピーして値を変更し、再度データを再割り当てする必要がある場合があります。つまり、

public void setValueAtIndex(int index , Object value){
      Object tempdata =  copy(data); // make a copy of that array
      //change in the copied array 
       tempdata[index] = value; 
// reassign the array back to original array
 data = tempData;   
}

上記のアプローチを使用すると、配列を書き込むコストで配列を読み取るパフォーマンスが向上します。固定長の配列がある場合は同期する必要はありません。それ以外の場合は、ミューテーション操作のためにロックが必要です

于 2013-08-02T07:34:59.460 に答える
0

スレッドが値を書き込むだけなのか、それとも読み取るのか (たとえば、値を 1 ずつインクリメントするため) によって異なります。それらが読み取られた場合、読み取りと書き込みの両方のすべての値をカバーする領域で同期します。異なるセルから読み取る場合は、最初のバリアントです。同じ販売からのみの場合は、2 番目のバリアントです。値が読み取られない場合は、同期する必要はまったくありません。

于 2013-08-01T12:45:34.997 に答える
0

私は解決策1を選択します:

私はそれがあなたのニーズに完全に合っていると思います.

パフォーマンスの問題は無視できると思います。

synchronize 

あなたのアクセスは仕事をします。なぜそれをそれよりも難しくするのですか。

ヒント:配列は使用しません。Collectionを使用することをお勧めします。あなたが必要とするすべての人のためのコレクションがあります。

于 2013-08-01T10:58:25.870 に答える
0

Java では、配列の使用方法に応じて、代わりに AbstractQueue ArrayList に値を入れることができます。これは便利なjava.util.concurrent.ConcurrentLinkedQueueの 1 つです。

または同様のキューのいずれか

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingDeque
  • 同期キュー
于 2013-08-01T10:54:58.503 に答える