web-dev-qa-db-ja.com

javaでArrayListを同期する正しい方法

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

ArrayListin_queueは、registerInQueue関数から渡されます。

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);
    }
}
34
bob

あなたは2回同期していますが、これは無意味であり、コードを遅くする可能性があります:リストの繰り返し中の変更は、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()は無駄な追加オーバーヘッドにすぎません。

44

あなたの例を見てみると、 ArrayBlockingQueue (またはその兄弟)が役に立つかもしれません。同期はユーザーに代わって行われるため、スレッドは追加の同期作業なしでキューに書き込んだり、ピーク/テイクを取得したりできます。

8
Brian Agnew

それは正しく、文書化されています:

http://Java.Sun.com/javase/6/docs/api/Java/util/Collections.html#synchronizedList(Java.util.List)

ただし、リストをクリアするには、 List.clear() を呼び出すだけです。

5
Andrew Duffy

はい、それは正しい方法ですが、すべての削除を一緒に安全にしたい場合は、同期ブロックが必要です-キューが空でない限り、削除は許可されません。私の推測では、安全なキュー操作とデキュー操作だけが必要なので、同期ブロックを削除できます。

ただし、Javaなど ConcurrentLinkedQueue などの非常に高度な並行キューがあります

5

通常のリスト(ArrayListクラスで実装)を取得して、同期させましょう。これはSynchronizedListExampleクラスに示されています。 Collections.synchronizedListメソッドに新しい文字列のArrayListを渡します。このメソッドは、文字列の同期リストを返します。 // SynchronizedArrayListクラスです

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());
            }
        }    
    }
}

リストを繰り返し処理する場合、このアクセスは、まだsynchronizedListオブジェクトをロックする同期ブロックを使用して行われます。一般に、同期されたコレクションの繰り返しは、同期されたブロックで実行する必要があります

1
user4423251