2010-03-14 10 views
68

Tengo un ArrayList que quiero usar para contener 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.¿Cómo hago mi ArrayList Thread-Safe? ¿Otro enfoque al problema en Java?

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 del compilador:

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

Este es el código correspondiente:

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, estoy usando un enfoque correcto y si no, ¿qué debo usar para hacer que mi código sea seguro para subprocesos? ¡Gracias por la ayuda!

+2

(Nota , la interfaz 'List' no es lo suficientemente completa como para ser muy útil en multihebras.) –

+3

Me gustaría señalar que, sin' Collections.synchronizedList() ', tendremos una condición de carrera REAL aquí: P –

Respuesta

106

Utilice Collections.synchronizedList().

Ex:

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

¡Gracias! No estoy seguro de por qué no pensé usar un Vector porque recuerdo haber leído en algún lugar que estaban sincronizados. – ericso

+29

Quizás no sea una buena idea trabajar con clases que se definen como obsoletas. – frandevel

+1

Aunque Vector es bastante antiguo y no admite Colecciones, no está en desuso. Probablemente sea mejor usar Collections.synchronizedList() como otras personas dijeron aquí. – Asturio

33

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) 

Lista es un supertipo de ArrayList por lo que deberá especificar que.

De lo contrario, lo que está haciendo parece estar bien. Otra opción es usar Vector, que está sincronizado, pero esto es probablemente lo que yo haría.

+1

O 'List' probablemente sería más útil. O 'List '. –

+0

Buen punto, hazlo privado List finishingOrder = Collections.synchronizedList (...) –

+0

Intenté esto y el compilador ahora se queja de que llamé a los métodos ArrayList en una Colección: '// Imprime el ganador System.out.println ("The Winner is" + ((RaceCar) finishingOrder.get (0)). ToString() + "!"); ' Está diciendo que el método get (0) no se encuentra. ¿Pensamientos? – ericso

0

Puede cambiar de ArrayList el tipo de vector, en el que se sincroniza cada método.

private Vector finishingOrder; 
//Make a Vector to hold RaceCar objects to determine winners 
finishingOrder = new Vector(numberOfRaceCars); 
+3

Si va a sugerir el uso de otra colección, probablemente Vector es una mala elección. Es una colección heredada que se adaptó al diseño del nuevo Java Collections Framework. Estoy seguro de que hay mejores opciones en el paquete java.until.concurrent. –

5

Usted puede a utilizar 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 automóviles 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.

+0

Ese es un buen punto. Esto es solo un ejercicio de un texto que estoy usando para aprender Java. El objetivo era aprender a usar los hilos y en realidad voy más allá de las especificaciones originales del problema al crear un mecanismo para registrar a los ganadores.Pensé en usar un temporizador para medir a los ganadores. Pero, sinceramente, creo que obtuve lo que necesitaba del ejercicio. – ericso

2

También puede utilizar la palabra clave para synchronizedaddFinisher método como este

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

Así que usted puede utilizar ArrayList añadir método seguro para subprocesos con esta forma.

+3

, pero ¿y si tienes dos métodos: addFinisher y delFinisher? Ambos métodos son seguros para la ejecución de subprocesos, pero como ambos acceden a la misma ArrayList, aún así tendrían problemas. – masi

+0

@masi Entonces simplemente sincroniza en un 'Objeto final' en su lugar cada vez que accede a la' Colección' de cualquier manera. – mkuech

6

CopyOnWriteArrayList

Uso CopyOnWriteArrayList clase. Esta es la versión segura para subprocesos de ArrayList.

+2

Piense dos veces al considerar esta clase. Para citar el documento de la clase: "Esto es generalmente demasiado costoso, pero puede ser más eficiente que las alternativas cuando las operaciones cruzadas superan en gran medida a las mutaciones, y es útil cuando no puede o no desea sincronizar recorridos, pero necesita evitar la interferencia entre hilos concurrentes . "Además, consulte [Diferencia entre CopyOnWriteArrayList y synchronizedList] (http://stackoverflow.com/q/28979488/642706) –

+0

esta clase entra en juego cuando usted rara vez modifica la lista, pero a menudo itera sobre los elementos. p.ej. cuando tienes un grupo de oyentes los registra y luego itera mucho ..., si no necesita explícitamente la interfaz de la lista, pero modifica y lee las operaciones para que sean concurrentes, considere 'ConcurrentLinkedQueue' – benez

0

Siempre que desee utilizar la versión segura de ant y thread del objeto de colección de hormigas, tome la ayuda de java.util.concurrent. * package. Tiene casi toda la versión concurrente de objetos de colección no sincronizados. por ejemplo: para ArrayList, tiene java.util.concurrent.CopyOnWriteArrayList

Puede hacer Collections.synchronizedCollection (cualquier objeto de colección), pero recuerde este clásico synchr. La técnica es costosa y viene con una sobrecarga de rendimiento. java.util.concurrent. * Paquete es menos costoso y gestionar el rendimiento de una mejor manera mediante el uso de mecanismos como

copy-on-write,compare-and-swap,Lock,snapshot iterators,etc.

Por lo tanto, prefiero algo de java.util.concurrent. * Paquete de

Cuestiones relacionadas