web-dev-qa-db-ja.com

ArrayListをスレッドセーフにするにはどうすればよいですか? Javaの問題に対する別のアプローチ?

実行が終了するとすぐにThreadクラスを拡張するRaceCarオブジェクトを保持するために使用したいArrayListがあります。 Raceと呼ばれるクラスは、RaceCarオブジェクトが実行を終了したときに呼び出すコールバックメソッドを使用して、このArrayListを処理します。コールバックメソッドaddFinisher(RaceCar finisher)は、RaceCarオブジェクトをArrayListに追加します。これは、スレッドが実行を終了する順序を提供することになっています。

ArrayListは同期されていないため、スレッドセーフではないことを知っています。新しいArrayListを渡し、返されたCollectionをArrayListに割り当てることで、Collections.synchronizedCollection(c Collection)メソッドを使用してみました。ただし、これによりコンパイラエラーが発生します。

Race.Java:41: incompatible types
found   : Java.util.Collection
required: Java.util.ArrayList
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));

関連するコードは次のとおりです。

public class Race implements RaceListener {
    private Thread[] racers;
    private ArrayList finishingOrder;

    //Make an ArrayList to hold RaceCar objects to determine winners
    finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));

    //Fill array with RaceCar objects
    for(int i=0; i<numberOfRaceCars; i++) {
    racers[i] = new RaceCar(laps, inputs[i]);

        //Add this as a RaceListener to each RaceCar
        ((RaceCar) racers[i]).addRaceListener(this);
    }

    //Implement the one method in the RaceListener interface
    public void addFinisher(RaceCar finisher) {
        finishingOrder.add(finisher);
    }

私が知る必要があるのは、正しいアプローチを使用していますか?そうでない場合、コードをスレッドセーフにするために何を使用する必要がありますか?助けてくれてありがとう!

80
ericso

Collections.synchronizedList() を使用します。

例:

Collections.synchronizedList(new ArrayList<YourClassNameHere>())
127
Amir Afghani

変化する

private ArrayList finishingOrder;

//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars)

private List finishingOrder;

//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedList(new ArrayList(numberOfRaceCars)

ListはArrayListのスーパータイプなので、指定する必要があります。

そうでなければ、あなたがやっていることはうまくいくようです。他のオプションとして、同期されたベクターを使用できますが、これはおそらく私が行うことです。

35
Reverend Gonzo

CopyOnWriteArrayList

CopyOnWriteArrayList クラスを使用します。これは、 ArrayList のスレッドセーフバージョンです。

10
Singh Piyush

might間違ったアプローチを使用しています。車をシミュレートする1​​つのスレッドが別の車シミュレーションスレッドの前に終了するからといって、最初のスレッドがシミュレートされたレースに勝つことを意味するわけではありません。

アプリケーションに大きく依存しますが、レースが完了するまで、短い時間間隔ですべての車の状態を計算する1つのスレッドを用意する方がよい場合があります。または、複数のスレッドを使用する場合は、各車がレースを完了するのにかかった「シミュレートされた」時間を記録し、最短時間で勝者を選択します。

6
erickson

このようなsynchronizedメソッドにaddFinisherキーワードを使用することもできます

    //Implement the one method in the RaceListener interface
    public synchronized void addFinisher(RaceCar finisher) {
        finishingOrder.add(finisher);
    }

したがって、この方法でArrayList addメソッドをスレッドセーフに使用できます。

4
erhun

Antスレッドセーフバージョンのantコレクションオブジェクトを使用する場合は、Java.util.concurrent。*パッケージを利用してください。同期されていないコレクションオブジェクトのほぼすべての同時バージョンがあります。例:ArrayListには、Java.util.concurrent.CopyOnWriteArrayListがあります

Collections.synchronizedCollection(任意のコレクションオブジェクト)を実行できますが、この古典的な同期を覚えておいてください。この手法は高価であり、パフォーマンスのオーバーヘッドが伴います。 Java.util.concurrent。*パッケージは安価で、次のようなメカニズムを使用してパフォーマンスをより適切に管理します。

copy-on-write、compare-and-swap、Lock、snapshot iteratorsなど

つまり、Java.util.concurrent。*パッケージの何かを優先する

ベクトルはスレッドセーフであり、arraylistはそうではないため、代わりにVectorとして使用することもできます。ベクトルは古いですが、目的を簡単に解決できます。

ただし、次のコードのようにArraylistを同期させることができます。

Collections.synchronizedList(new ArrayList(numberOfRaceCars())); 
0
Naman jain

ArrayListからVectorタイプに変更でき、すべてのメソッドが同期されます。

private Vector finishingOrder;
//Make a Vector to hold RaceCar objects to determine winners
finishingOrder = new Vector(numberOfRaceCars);
0
darlinton