Как сделать мой ArrayList потокобезопасным? Другой подход к проблеме в Java?


у меня есть ArrayList, который я хочу использовать для хранения объектов RaceCar, которые расширяют класс Thread, как только они закончат выполнение. Класс, называемый Race, обрабатывает этот ArrayList с помощью метода обратного вызова, который вызывает объект RaceCar по завершении выполнения. Метод обратного вызова, addFinisher (RaceCar finisher), добавляет объект RaceCar в ArrayList. Это должно дать порядок, в котором потоки завершают выполнение.

Я знаю, что ArrayList не синхронизированы и, следовательно, не является потокобезопасным. Я пробовал использовать коллекции.метод synchronizedCollection (C Collection), передавая новый ArrayList и назначая возвращенную коллекцию ArrayList. Однако, это дает мне ошибку компилятора:

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

что мне нужно знать, я использую правильный подход, а если нет, то что я должен использовать, чтобы сделать мой код потокобезопасным? Спасибо за помощь!

8 76

8 ответов:

использовать Collections.synchronizedList().

Ex:

Collections.synchronizedList(new ArrayList<YourClassNameHere>())

изменить

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, поэтому вам нужно указать это.

в противном случае, то, что вы делаете, кажется прекрасным. Другой вариант - вы можете использовать вектор, который синхронизируется, но это, вероятно, то, что я бы сделал.

CopyOnWriteArrayList

использовать CopyOnWriteArrayList класса. Это потокобезопасная версия ArrayList.

вы может используйте неправильный подход. Просто потому, что один поток, который имитирует автомобиль, заканчивается до того, как другой поток моделирования автомобиля не означает, что первый поток должен выиграть моделируемую гонку.

Это во многом зависит от вашего приложения, но может быть лучше иметь один поток, который вычисляет состояние всех автомобилей через небольшие промежутки времени до завершения гонки. Или, если вы предпочитаете использовать несколько потоков, вы можете записать каждый автомобиль "имитация" время потребовалось, чтобы завершить гонку, и выбрать победителя, как тот, с самым коротким временем.

вы также можете использовать synchronized ключевое слово addFinisher способ такой

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

таким образом, Вы можете использовать ArrayList добавить метод потокобезопасный с этим способом.

вы можете перейти от ArrayList к векторному типу, в котором синхронизируется каждый метод.

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

всякий раз,когда вы хотите использовать Ant потокобезопасную версию объекта Ant collection, возьмите помощь java.утиль.параллельный.* пакета. Он имеет почти все параллельные версии несинхронизированных объектов коллекции. например: для ArrayList у вас есть java.утиль.параллельный.CopyOnWriteArrayList

вы можете делать коллекции.synchronizedCollection (любой объект коллекции),но помните этот классический synchr. техника стоит дорого и поставляется с производительностью накладные расходы. Ява.утиль.параллельный.* пакет является менее дорогостоящим и лучше управлять производительностью с помощью механизмов, таких как

копирование на запись, сравнение и обмен, блокировка, итераторы моментальных снимков и т. д.

Итак, предпочитаю что-то из java.утиль.параллельный.* пакет

вы также можете использовать в качестве вектора вместо этого, поскольку векторы потокобезопасны, а arraylist-нет. Хотя векторы старые, но они могут легко решить вашу цель.

но вы можете сделать свой Arraylist синхронизированным как код, учитывая это:

Collections.synchronizedList(new ArrayList(numberOfRaceCars()));