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

eri*_*cso 82 java collections multithreading synchronization arraylist

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

我知道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));
Run Code Online (Sandbox Code Playgroud)

这是相关代码:

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);
    }
Run Code Online (Sandbox Code Playgroud)

我需要知道的是,我使用了正确的方法,如果没有,我应该使用什么来使我的代码线程安全?谢谢您的帮助!

Ami*_*ani 130

使用Collections.synchronizedList().

例如:

Collections.synchronizedList(new ArrayList<YourClassNameHere>())
Run Code Online (Sandbox Code Playgroud)

  • 也许使用定义为已弃用的类不是一个好主意 (31认同)
  • -1评论.Vector不被弃用,它如何不支持集合?它实现了List.Vector的javadoc特别说:"从Java 2平台v1.2开始,这个类被改进以实现List接口,使其成为Java Collections Framework的成员.与新的集合实现不同,Vector是同步的." 可能有充分的理由不使用Vector(避免同步,更改实现),但是"过时"或"不现代"不是其中之一. (14认同)
  • 评论无关紧要,因为答案已被编辑,并且不再建议“Vector”。 (3认同)
  • 谢谢!我不确定为什么我不想只使用Vector,因为我记得在他们同步的地方读书. (2认同)

Rev*_*nzo 35

更改

private ArrayList finishingOrder;

//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars)
Run Code Online (Sandbox Code Playgroud)

private List finishingOrder;

//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedList(new ArrayList(numberOfRaceCars)
Run Code Online (Sandbox Code Playgroud)

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

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


小智 11

CopyOnWriteArrayList

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

  • 在考虑这门课时要三思而后行.引用类文档:"这通常成本太高,但是当遍历操作大大超过突变时,它可能比替代方法更有效,并且当您不能或不想同步遍历但需要排除并发线程之间的干扰时非常有用.另外,请参阅[CopyOnWriteArrayList和synchronizedList之间的区别](http://stackoverflow.com/q/28979488/642706) (3认同)
  • 当您很少修改列表但经常迭代元素时,这个类就会发挥作用。例如,当您有一组听众时。你注册它们,然后迭代很多...,如果你没有明确需要列表接口,但修改和读取操作是并发的,请考虑`ConcurrentLinkedQueue` (3认同)

eri*_*son 6

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

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


erh*_*hun 5

您也可以使用synchronized关键字作为这样的addFinisher方法

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

因此,您可以通过这种方式使用 ArrayList 添加方法线程安全。

  • 好吧,但是如果你有两个方法:addFinisher 和 delFinisher 呢?这两种方法都是线程安全的,但由于两者都访问相同的 ArrayList,因此您仍然会遇到麻烦。 (4认同)