2009-09-16 12 views
31

これが私のArrayListを同期する正しい方法であるかどうかはわかりません。正しい方法でJavaのArrayListを同期させる

私はregisterInQueue関数から渡されたArrayListin_queueを持っています。

ArrayList<Record> in_queue = null; 

public void registerInQueue(ArrayList in_queue) 
{ 
    this.in_queue = in_queue; 
} 

今私はそれを同期しようとしています。これは私のin_queueオブジェクトを正しく同期していますか?

正しいです
List<Record> in_queue_list = Collections.synchronizedList(in_queue); 

synchronized (in_queue_list) { 
    while (in_queue_list.size() > 0) { 
     in_queue_list.remove(0); 
    } 
} 
+5

参照が渡されているため、実際には所有していないため、リストを同期させることはできません。参照を与えたものは何でも、それを渡した元のリストを変更することができます。あなたが追加する同期に関係なく、そのリストが本質的なロックによって保護されることが明示されていない限り、 –

+0

私はキュー上の任意の操作の周りに同期ブロックを入れます。ありがとう! – bob

答えて

41

としてJavaではるかに高度な同時実行キューがありますsynchronized (in_queue_list)で実行している場合は、Collections.synchronizedList()を使用してください(個別の操作を同期させるラッパーが作成されます)。

しかし、あなたはリストを完全に空にしているので、最初の要素を反復削除するのは最悪の方法です。各要素をシースし、次の要素をすべてコピーして、これをO(n^2 )操作 - 大きなリストの場合はひどく遅くなります。

代わりに、clear()を呼び出してください。繰り返しは必要ありません。

編集: あなたが後でCollections.synchronizedList()のシングル方式の同期が必要な場合は、これは正しい方法である:

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 
in_queue_list.clear(); // synchronized implicitly, 

しかし、多くの場合、シングル方式の同期が不十分である(たとえば、すべての反復の場合、または値を取得した場合はそれに基づいて計算を行い、結果と置き換えます)。その場合は、とにかく手動同期を使用する必要があります。したがって、Collections.synchronizedList()は単なる追加のオーバーヘッドにすぎません。

+7

ここで2回の同期化は無意味ではありません。ループ実行中に他の誰もリストを変更できないようにします。しかし、 'clear()'を使用していないのは少しオーバーです。 :) – Bombe

+0

私は何かのようにする必要があります:synchronized((List)in_queue)? – bob

+0

私は実際にシンプルにするために少しのコードを削除しました。 clear()/ remove()に問題はありません。ありがとう=] – bob

5

はい、正しい方法ですが、すべての削除を一緒に安全にしたい場合は、同期ブロックが必要です。キューが空でない限り、削除は許可されません。私の推測では、安全なキュー操作とデキュー操作だけが必要なので、同期ブロックを削除することができます。変更内容をリストを反復処理しながら、全体的な動作を超えるsynchronnization必要があります。

しかし、あなたはどれが無意味であると多分遅くなるコードダウンし、二回同期しているようにConcurrentLinkedQueue

8

あなたの例を見ると、ArrayBlockingQueue(またはその兄弟)が役に立つかもしれません。彼らはあなたのための同期を見ますので、スレッドはあなたの部分で追加の同期作業なしでキューに書き込んだり、取りに行くことができます。

+0

提案していただきありがとうございます!それは私がやろうとしていることですが、私の配列のサイズを制限することについてはわかりません。私はこれを念頭に置いておきます。 ;) – bob

+0

LinkedBlockingQueueもあります。そして、あなたは必ずしも限界を課す必要はありません。 –

+0

ありがとう、私はこれを覚えています] – bob

1

(ArrayListクラスで実装されている)通常のリストを作り、それを同期させましょう。これは、SynchronizedListExampleクラスに表示されます。 Collections.synchronizedListメソッドにStringの新しいArrayListを渡します。このメソッドは、同期されたStringのリストを返します。ここ //はSynchronizedArrayListクラスは、リストを反復処理する場合、このアクセスはまだsynchronizedListオブジェクトにロック同期ブロックを使用して行われていること

package com.mnas.technology.automation.utility; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
import org.apache.log4j.Logger; 
/** 
* 
* @author manoj.kumar 
* @email [email protected] 
* 
*/ 
public class SynchronizedArrayList { 
    static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName()); 
    public static void main(String[] args) {  
     List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>()); 
     synchronizedList.add("Aditya"); 
     synchronizedList.add("Siddharth"); 
     synchronizedList.add("Manoj"); 
     // when iterating over a synchronized list, we need to synchronize access to the synchronized list 
     synchronized (synchronizedList) { 
      Iterator<String> iterator = synchronizedList.iterator(); 
      while (iterator.hasNext()) { 
       log.info("Synchronized Array List Items: " + iterator.next()); 
      } 
     }  
    } 
} 

お知らせです。 一般的に、同期化されたコレクションの反復処理は、同期化されたブロックで行う必要があります。

関連する問題