views:

453

answers:

4

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!

+2  A: 

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.

Milan Ramaiya
Or `List` would probably be more useful. Or `List<RaceCar>`.
Tom Hawtin - tackline
Good point, make it private List finishingOrder = Collections.synchronizedList(...)
Milan Ramaiya
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?
thechiman
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.
thechiman
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));
thechiman
right, make it Collections.synhronizedList(...)
Milan Ramaiya
+3  A: 

Why don't you just save yourself the headache and use a Vector, which is synchronized for you.

Amir Afghani
Thanks! I'm not sure why I didn't think to just use a Vector since I remember reading somewhere they were synchronized.
thechiman
A: 

You can change from ArrayList to Vector type, in which every method is synchronized.

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

You might be using the wrong approach. Just because one thread that simulates a care 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.

erickson
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.
thechiman