1

2 つの同時スレッドを実行しようとしています。1 つはオブジェクトをリストに追加し続け、もう 1 つはこれらのオブジェクトを更新し、これらのオブジェクトの一部をリストから削除することもあります。メソッドとクラスに使用したプロジェクト全体があるArrayListため、現在変更するのは困難です。

私は周りを見回して、これを行ういくつかの方法を見つけましたが、私が言ったように、から変更するのは難しいArrayList. オブジェクトをリストに追加するメソッドと、これらのオブジェクトを変更し、特定の基準を満たした場合に削除する可能性のあるメソッドに対して、 synchronizedandを使用してみました。notify()wait()

を使用してこれを行う方法を理解しましたが、それ自体を使用してこれをシミュレートCopyOnWriteArrayListする可能性があるかどうかを知りたいです。ArrayListコード全体を編集する必要がないように。

したがって、基本的には、次のようなことをしたいと思いますが、次のようになりますArrayList

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

public class ListExample{
    CopyOnWriteArrayList<MyObject> syncList;

    public ListExample(){
        syncList = new CopyOnWriteArrayList<MyObject>();

        Thread thread1 = new Thread(){
            public void run(){
                synchronized (syncList){
                    for(int i = 0; i < 10; i++){
                        syncList.add(new MyObject(i));
                    }
                }
            }
        };

        Thread thread2 = new Thread(){
            public void run(){
                synchronized (syncList){
                    Iterator<MyObject> iterator = syncList.iterator();
                    while(iterator.hasNext()){
                        MyObject temp = iterator.next();

                        //this is just a sample list manipulation
                        if (temp.getID() > 3)
                            syncList.remove(temp);

                        System.out.println("Object ID: " + temp.getID() + " AND list size: " + syncList.size());
                    }
                }
            }
        };

        thread1.start();
        thread2.start();
    }

    public static void main(String[] args){
        new ListExample();
    }
}

class MyObject{
    private int ID;

    public MyObject(int ID){
        this.ID = ID;
    }

    public int getID(){
        return ID;
    }

    public void setID(int ID){
        this.ID = ID;
    }
}

私も読んだことCollections.synchronizedList(new ArrayList())がありますが、パラメーターとして受け取るメソッドがかなりの数あるため、コードを変更する必要があると思いArrayListます。

私はアイデアがないので、どんなガイダンスもいただければ幸いです。ありがとうございました。

4

4 に答える 4

1

もちろん、パッケージを使用する必要がありますjava.util.concurrentArrayListしかし、同期のみで何が起こっているか、または何が起こる可能性があるかを見てみましょう。

あなたのコードではArrayList、 の代わりに がある場合、スレッドで行っている/操作しているものすべてにCopyOnWriteArrayList完全な同期を提供しているため、機能するはずです。全体が同期されている場合synchronized (syncList)は必要ありません(ただし、それはお勧めしませんが、そうなるでしょう)。wait() notify()

ただし、ConcurrentModificationExceptionイテレータsyncList.iterator()を使用すると、そのリストから要素を削除しないでください。そうしないと、反復中に望ましくない結果が生じる可能性があるため、高速に失敗して例外を発生させるように設計されています。これを回避するには、次のように使用できます。

                Iterator<MyObject> iterator = syncList.iterator();
                ArrayList<MyObject> toBeRemoved = new ArrayList<MyObject>();
                while(iterator.hasNext()){
                    MyObject temp = iterator.next();

                    //this is just a sample list manipulation
                    if (temp.getID() > 3)
                    {
                        //syncList.remove(temp);
                        toBeRemoved.add(temp);
                    }
                    System.out.println("Object ID: " + temp.getID() + " AND list size: " + syncList.size());
                }
                syncList.removeAll(toBeRemoved);

同期に関しては、スコープを最小限に抑えるように努める必要があります。そうしないと、スレッド間で不要な待機が発生します。そのため、java.util.concurrent パッケージはマルチスレッドで高いパフォーマンスを発揮するように指定されています (非ブロッキング アルゴリズムを使用しても)。または、使用することもできますが、クラスCollections.synchronizedList(new ArrayList())ほど良くありません。concurrent

wait() notify()プロデューサー/コンシューマーの問題のように条件付き同期を使用する場合は、同じオブジェクト (ロック) でメカニ​​ズムを使用できます。しかし、ここでも、使用のように役立ついくつかのクラスが既にありますjava.util.concurrent.LinkedBlockingQueue

于 2013-03-12T06:15:04.597 に答える