如何使我的ArrayList线程安全? Java中另一种解决问题的方法?

时间:2010-03-14 22:18:27

标签: java multithreading collections synchronization arraylist

我有一个ArrayList,我想用它来保存RaceCar对象,一旦完成执行就会扩展Thread类。一个名为Race的类使用RaceCar对象在完成执行时调用的回调方法处理此ArrayList。回调方法addFinisher(RaceCar finisher)将RaceCar对象添加到ArrayList。这应该给出线程完成执行的顺序。

我知道ArrayList不是同步的,因此不是线程安全的。我尝试使用Collections.synchronizedCollection(c Collection)方法,传入一个新的ArrayList并将返回的Collection分配给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 个答案:

答案 0 :(得分:122)

使用Collections.synchronizedList()

例如:

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

答案 1 :(得分:35)

更改

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的超类型,因此您需要指定。

否则,你所做的似乎很好。其他选项是你可以使用同步的Vector,但这可能就是我要做的。

答案 2 :(得分:9)

CopyOnWriteArrayList

使用CopyOnWriteArrayList课程。这是ArrayList的线程安全版本。

答案 3 :(得分:6)

可能使用了错误的方法。仅仅因为模拟汽车的一个线程在另一个汽车仿真线程之前完成并不意味着第一个线程应该赢得模拟竞赛。

这在很大程度上取决于您的应用程序,但最好让一个线程以较小的时间间隔计算所有汽车的状态,直到比赛结束。或者,如果您更喜欢使用多个线程,您可能会让每辆车记录完成比赛所需的“模拟”时间,并选择获胜者作为最短时间的获胜者。

答案 4 :(得分:4)

您也可以synchronized方法使用addFinisher关键字

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

所以你可以用这种方式使用ArrayList add方法线程安全。

答案 5 :(得分:0)

您可以从ArrayList更改为Vector类型,其中每个方法都是同步的。

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

答案 6 :(得分:0)

每当您想使用ant线程安全版本的ant集合对象时,请使用 java.util.concurrent。* 包的帮助。 它几乎具有所有并发版本的非同步集合对象。例如:对于ArrayList,你有java.util.concurrent.CopyOnWriteArrayList

你可以做Collections.synchronizedCollection(任何集合对象),但要记住这个经典的同步。技术昂贵,并带来性能开销。 java.util.concurrent。*包比较便宜,并且通过使用

等机制以更好的方式管理性能
  

写时复制,比较和交换,锁,快照迭代器等

所以,首选来自java.util.concurrent。* package

答案 7 :(得分:0)

您也可以使用Vector作为向量,因为向量是线程安全的而arraylist不是。 虽然矢量很老但是它们可以很容易地解决你的目的。

但是你可以让你的Arraylist像代码一样同步:

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