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

如何使ArrayList线程安全?Java中解决问题的另一种方法?,java,multithreading,collections,synchronization,arraylist,Java,Multithreading,Collections,Synchronization,Arraylist,我有一个ArrayList,我想用它来保存RaceCar对象,这些对象在完成执行后立即扩展Thread类。名为Race的类使用RaceCar对象在完成执行时调用的回调方法来处理此ArrayList。回调方法addFinisher(RaceCar finisher)将RaceCar对象添加到ArrayList。这应该给出线程完成执行的顺序 我知道ArrayList是不同步的,因此不是线程安全的。我尝试使用Collections.synchronizedCollection(c Collection

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

我知道ArrayList是不同步的,因此不是线程安全的。我尝试使用Collections.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);
    }
公共类Race实现RaceListener{
私家车;
私人ArrayList finishingOrder;
//制作一个ArrayList以保存赛车对象以确定胜利者
finishingOrder=Collections.synchronizedCollection(新数组列表(赛车数量));
//用赛车对象填充数组
对于(inti=0;i变化

private ArrayList finishingOrder;

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

List是ArrayList的超类型,因此需要指定它

另外一个选择是可以使用向量,它是同步的,但这可能就是我要做的。

使用

例:

Collections.synchronizedList(新的ArrayList())

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

private Vector finishingOrder;
//Make a Vector to hold RaceCar objects to determine winners
finishingOrder = new Vector(numberOfRaceCars);
您可能使用了错误的方法。仅仅因为一个模拟汽车的线程在另一个汽车模拟线程之前完成,并不意味着第一个线程应该赢得模拟比赛


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

您也可以使用
synchronized
关键字作为
addFinisher
方法,如下所示

    //Implement the one method in the RaceListener interface
    public synchronized void addFinisher(RaceCar finisher) {
        finishingOrder.add(finisher);
    }
因此,您可以通过这种方式使用ArrayList add方法线程安全。

CopyOnWriteArrayList

使用类。这是的线程安全版本。

每当您想使用ant集合对象的ant线程安全版本时,请借助java.util.concurrent.包。 它几乎拥有所有未同步集合对象的并发版本

您可以执行Collections.synchronizedCollection(任何集合对象),但请记住,这种经典的synchr.technology非常昂贵,而且会带来性能开销。 java.util.concurrent.*包的成本更低,并且通过使用如下机制以更好的方式管理性能

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


因此,您更喜欢java.util.concurrent.*package中的内容,因为向量是线程安全的,而arraylist不是。 虽然向量很古老,但它们可以很容易地解决您的目的

但是,您可以使Arraylist像以下代码一样同步:

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

或者
List
可能会更有用。或者
List
。好的一点,让它成为私有列表finishingOrder=Collections.synchronizedList(…)我尝试了这个,编译器现在抱怨我调用了集合上的ArrayList方法:
//Print out winner System.out.println(“获胜者是”+((赛车)finishingOrder.get(0)).toString()+“!”;
表示get(0)找不到方法。想法?很抱歉删除并重新添加我的注释。我试图使用反勾号使突出显示正常工作。我得到了关于此类内容的OCD。不,这不起作用。它不会将集合强制转换为列表:Race.java:41:找到的不兼容类型:java.util.Collection required:java.util.ListishingOrder=Collections.synchronizedCollection(新的ArrayList(numberOfRaceCars));(注意,
List
接口不够完整,在多线程处理中不太有用。)我只想指出,如果没有
Collections.synchronizedList()
,我们这里会有一个真正的竞争条件:p检查此链接,谢谢!我不知道为什么我不想只使用向量,因为我记得在某个地方读到它们是同步的。虽然向量非常旧,并且没有集合支持,但它并没有被弃用。使用集合可能更好。synchronizedList()正如其他人在这里所说,-1用于评论。Vector没有被弃用,它如何没有集合支持?它实现了列表。Vector的javadoc特别指出:“从Java 2平台v1.2开始,该类经过改装以实现列表接口,使其成为Java集合框架的成员。与新的集合实现不同,Vector是同步的。”不使用Vector(避免同步,更改实现)可能有很好的理由,但“过时”或”使用以下方法:Collections.synchronizedList(list);Collections.synchronizedSet(set);Collections.synchronizedMap(map);上述方法将集合作为参数,并返回相同类型的集合,这些集合是同步的和线程安全的。注释是不相关的,因为答案已被编辑,并且不再建议
Vector
。这是一个很好的观点。这只是我用来学习Java的文本中的一个练习。重点是学习如何使用线程和事实上,我在建立一个记录获奖者的机制时超出了问题的原始规格。我考虑过使用计时器来测量获奖者。但老实说,我认为我已经从这个练习中得到了我所需要的。如果你打算建议使用另一个集合,请使用pro
    //Implement the one method in the RaceListener interface
    public synchronized void addFinisher(RaceCar finisher) {
        finishingOrder.add(finisher);
    }
Collections.synchronizedList(new ArrayList(numberOfRaceCars()));