How do I make my ArrayList Thread-Safe? Another approach to problem in Java?

207,458

Solution 1

Use Collections.synchronizedList().

Ex:

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

Solution 2

Change

private ArrayList finishingOrder;

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

to

private List finishingOrder;

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

List is a supertype of ArrayList so you need to specify that.

Otherwise, what you're doing seems fine. Other option is you can use Vector, which is synchronized, but this is probably what I would do.

Solution 3

CopyOnWriteArrayList

Use CopyOnWriteArrayList class. This is the thread safe version of ArrayList.

Solution 4

You might be using the wrong approach. Just because one thread that simulates a car finishes before another car-simulation thread doesn't mean that the first thread should win the simulated race.

It depends a lot on your application, but it might be better to have one thread that computes the state of all cars at small time intervals until the race is complete. Or, if you prefer to use multiple threads, you might have each car record the "simulated" time it took to complete the race, and choose the winner as the one with shortest time.

Solution 5

You can also use synchronized keyword for addFinisher method like this

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

So you can use ArrayList add method thread-safe with this way.

Share:
207,458

Related videos on Youtube

ericso
Author by

ericso

E is for Erudite

Updated on July 08, 2022

Comments

  • ericso
    ericso almost 2 years

    I have an ArrayList that I want to use to hold RaceCar objects that extend the Thread class as soon as they are finished executing. A class, called Race, handles this ArrayList using a callback method that the RaceCar object calls when it is finished executing. The callback method, addFinisher(RaceCar finisher), adds the RaceCar object to the ArrayList. This is supposed to give the order in which the Threads finish executing.

    I know that ArrayList isn't synchronized and thus isn't thread-safe. I tried using the Collections.synchronizedCollection(c Collection) method by passing in a new ArrayList and assigning the returned Collection to an ArrayList. However, this gives me a compiler error:

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

    Here is the relevant code:

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

    What I need to know is, am I using a correct approach and if not, what should I use to make my code thread-safe? Thanks for the help!

    • Brett
      Brett about 14 years
      (Note, the List interface isn't really complete enough to be very useful in multithreading.)
    • Dylan Watson
      Dylan Watson over 9 years
      I'd just like to point out that, without Collections.synchronizedList(), we'd have a REAL race condition here :P
    • rishi007bansod
      rishi007bansod over 5 years
  • Brett
    Brett about 14 years
    Or List would probably be more useful. Or List<RaceCar>.
  • Reverend Gonzo
    Reverend Gonzo about 14 years
    Good point, make it private List finishingOrder = Collections.synchronizedList(...)
  • ericso
    ericso about 14 years
    I tried this and the compiler is now complaining about me calling ArrayList methods on a Collection: //Print out winner System.out.println("The Winner is " + ((RaceCar) finishingOrder.get(0)).toString() + "!"); It is saying the get(0) method is not found. Thoughts?
  • ericso
    ericso about 14 years
    Sorry about deleting and re-adding my comment. I was trying to get the highlighting to work using backticks. I get OCD about that kind of stuff.
  • ericso
    ericso about 14 years
    No, that doesn't work. It won't cast the Collection to a List: Race.java:41: incompatible types found : java.util.Collection required: java.util.List finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));
  • ericso
    ericso about 14 years
    Thanks! I'm not sure why I didn't think to just use a Vector since I remember reading somewhere they were synchronized.
  • ericso
    ericso about 14 years
    That's a good point. This is just an exercise from a text I'm using to learn Java. The point was to learn how to use threads and I'm actually going beyond the original specifications of the problem in building a mechanism to log the winners. I though about using a timer to measure the winners. But honestly, I think I've gotten what I need from the exercise.
  • Asturio
    Asturio almost 11 years
    Although Vector is quite old and lacks Collections-support, it is not deprecated. It is probably better to use Collections.synchronizedList() like other people said here.
  • fool4jesus
    fool4jesus over 10 years
    -1 for comments. Vector is not deprecated and how does it not have collections support? It implements List. The javadoc for Vector specifically says: "As of the Java 2 platform v1.2, this class was retrofitted to implement the List interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Vector is synchronized." There may be good reasons for not using Vector (avoiding synchronization, changing out implementations), but being "obsolete" or "not modern" isn't one of them.
  • Edwin Dalorzo
    Edwin Dalorzo about 10 years
    If you are going to suggest using another collection, probably Vector is a poor choice. It is a legacy collection which was retrofitted to the design of the new Java Collections Framework. I am sure there are better choices in the java.until.concurrent package.
  • omni
    omni almost 10 years
    well, but what if you got two methods: addFinisher and delFinisher? Both methods are thread-safe but since both access the same ArrayList you would still get trouble.
  • Sameer Kazi
    Sameer Kazi about 9 years
    Use below methods: Collections.synchronizedList(list); Collections.synchronizedSet(set); Collections.synchronizedMap(map); Above methods take collection as parameter and return same type of collection which are synchronized and thread safe.
  • mkuech
    mkuech over 8 years
    @masi Then you just synchronize on a final Object instead every time you access the Collection in any way.
  • Basil Bourque
    Basil Bourque over 7 years
    Think twice when considering this class. To quote the class doc: ”This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads.” Also, see Difference between CopyOnWriteArrayList and synchronizedList
  • benez
    benez over 7 years
    this class comes into play when you rarely modify the list, but often iterate over the elements. e.g. when you have a set of listeners. you register them and then you iterate a lot..., if you don't explicitly need the list interface, but modify and read operations to be concurrent, consider ConcurrentLinkedQueue
  • Koray Tugay
    Koray Tugay over 3 years
    Comments are irrelevant as answer has been edited and is not suggesting Vector anymore.