¿Cómo puedo hacer mi ArrayList Thread-Safe? ¿Otro enfoque al problema en Java?
multithreading collections (8)
Tengo una ArrayList que quiero usar para contener los objetos RaceCar que extienden la clase Thread tan pronto como terminan de ejecutarse. Una clase, llamada Race, maneja este ArrayList utilizando un método de devolución de llamada que el objeto RaceCar llama cuando termina de ejecutarse. El método de devolución de llamada, addFinisher (Finalizador RaceCar), agrega el objeto RaceCar a ArrayList. Se supone que esto da el orden en que los hilos terminan de ejecutarse.
Sé que ArrayList no está sincronizado y, por lo tanto, no es seguro para subprocesos. Intenté utilizar el método Collections.synchronizedCollection (c Collection) al pasar una nueva ArrayList y asignar la Colección devuelta a una ArrayList. Sin embargo, esto me da un error de compilación:
Race.java:41: incompatible types
found : java.util.Collection
required: java.util.ArrayList
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars));
Aquí está el código relevante:
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);
}
Lo que necesito saber es si utilizo un enfoque correcto y, de no ser así, ¿qué debo usar para que mi código sea seguro para subprocesos? ¡Gracias por la ayuda!
CopyOnWriteArrayList
Use la clase CopyOnWriteArrayList
. Esta es la versión segura de subprocesos de ArrayList
.
Cambio
private ArrayList finishingOrder;
//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedCollection(new ArrayList(numberOfRaceCars)
a
private List finishingOrder;
//Make an ArrayList to hold RaceCar objects to determine winners
finishingOrder = Collections.synchronizedList(new ArrayList(numberOfRaceCars)
List es un supertipo de ArrayList, por lo que debe especificarlo.
De lo contrario, lo que estás haciendo parece estar bien. Otra opción es usar Vector, que está sincronizado, pero esto es probablemente lo que yo haría.
Puede cambiar de ArrayList a Vector type, en el que todos los métodos están sincronizados.
private Vector finishingOrder;
//Make a Vector to hold RaceCar objects to determine winners
finishingOrder = new Vector(numberOfRaceCars);
Puede estar utilizando el enfoque equivocado. El hecho de que un hilo que simula un automóvil termina antes de otro hilo de simulación de automóvil no significa que el primer hilo debería ganar la carrera simulada.
Depende mucho de su aplicación, pero podría ser mejor tener un hilo que calcule el estado de todos los autos en pequeños intervalos de tiempo hasta que se complete la carrera. O, si prefiere usar varios hilos, puede hacer que cada carro registre el tiempo "simulado" que tomó completar la carrera, y elija al ganador como el que tenga el tiempo más corto.
Siempre que desee usar la versión ant thread safe del objeto ant de colección, tome la ayuda del paquete java.util.concurrent. * . Tiene casi toda la versión concurrente de objetos de colección no sincronizados. por ejemplo: para ArrayList, tiene java.util.concurrent.CopyOnWriteArrayList
Puedes hacer Collections.synchronizedCollection (cualquier objeto de colección), pero recuerda este clásico synchr. La técnica es costosa y viene con una sobrecarga de rendimiento. El paquete java.util.concurrent. * es menos costoso y gestiona el rendimiento de una mejor manera mediante el uso de mecanismos como
copy-on-write, compare-and-swap, Lock, iteradores de instantáneas, etc.
Por lo tanto, prefiera algo del paquete java.util.concurrent. *
También puede usar synchronized
palabra clave synchronized
para el método addFinisher
como este
//Implement the one method in the RaceListener interface
public synchronized void addFinisher(RaceCar finisher) {
finishingOrder.add(finisher);
}
Entonces puede usar ArrayList add method thread-safe de esta manera.
También puede usar como Vector en su lugar, ya que los vectores son seguros para la ejecución de subprocesos y los de arrays no. Aunque los vectores son viejos pero pueden resolver su propósito fácilmente.
Pero puede hacer que su Arraylist se sincronice como el código dado a esto:
Collections.synchronizedList(new ArrayList(numberOfRaceCars()));
Use Collections.synchronizedList()
.
Ex:
Collections.synchronizedList(new ArrayList<YourClassNameHere>())