How do I make my ArrayList Thread-Safe? Another approach to problem in Java?
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.
Related videos on Youtube
Comments
-
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 about 14 years(Note, the
List
interface isn't really complete enough to be very useful in multithreading.) -
Dylan Watson over 9 yearsI'd just like to point out that, without
Collections.synchronizedList()
, we'd have a REAL race condition here :P -
rishi007bansod over 5 yearsCheck this link programmerzdojo.com/java-tutorials/…
-
-
Brett about 14 yearsOr
List
would probably be more useful. OrList<RaceCar>
. -
Reverend Gonzo about 14 yearsGood point, make it private List finishingOrder = Collections.synchronizedList(...)
-
ericso about 14 yearsI 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 about 14 yearsSorry 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 about 14 yearsNo, 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 about 14 yearsThanks! I'm not sure why I didn't think to just use a Vector since I remember reading somewhere they were synchronized.
-
ericso about 14 yearsThat'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 almost 11 yearsAlthough 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 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 about 10 yearsIf 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 almost 10 yearswell, 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 about 9 yearsUse 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 over 8 years@masi Then you just synchronize on a
final Object
instead every time you access theCollection
in any way. -
Basil Bourque over 7 yearsThink 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 over 7 yearsthis 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 over 3 yearsComments are irrelevant as answer has been edited and is not suggesting
Vector
anymore.