2011-10-03 11 views
16

Estoy haciendo un programa en java que compite con algunos coches uno contra el otro. Cada automóvil es un hilo separado.¿El operador de preincremento es seguro para subprocesos?

Cuando los autos completan la carrera, cada uno de ellos llama a este método. He probado el método a diferentes velocidades de temporizador, y parece funcionar bien. Pero me doy cuenta de que cada hilo está accediendo a la variable carsComplete, a veces exactamente al mismo tiempo (al menos en el alcance que me da el comando date).

Así que mi pregunta es: ¿este método es seguro para subprocesos?

public static String completeRace() 
{ 
     Date accessDate = new Date(); 
     System.out.println("Cars Complete: " + carsComplete + " Accessed at " + accessDate.toString()); 
     switch(++carsComplete) 
     { 
      case 1: return "1st"; 
      case 2: return "2nd"; 
      case 3: return "3rd"; 
      default: return carsComplete + "th";  
     } 
} 

Respuesta

19

No, usted debe utilizar algo así como java.util.concurrent.atomic.AtomicInteger. Mira su método getAndIncrement().

+3

O sincronice en algo antes de incrementar. –

+1

@Ted: Apuesto a que sincronizar algo es más caro. –

+1

@Eric - Me sorprendería si AtomicInteger no hiciera alguna sincronización en algún momento (tal vez en código nativo). Sería interesante hacer una evaluación comparativa. Desde la fuente de AtomicInteger, parece depender de un algoritmo de comparación y ajuste atómico que vuelve a intentar hasta que no detecta ningún problema. No hay el peor de los casos obligado para esto; en escenarios altamente enhebrados, creo que podría ser muy lento en momentos aleatorios. –

5

++ operador no es atómico. Mira aquí http://madbean.com/2003/mb2003-44/. Para las operaciones atómicas puede utilizar AtomicInteger

AtomicInteger atomicInteger = new java.util.concurrent.atomic.AtomicInteger(0) 

y cada vez que desea incrementar puede llamar atomicInteger.incrementAndGet() método que devuelve un int primitivo. 0 es el valor inicial predeterminado para el número entero atómico.

+0

¿Todavía no entiendo por qué las operaciones atómicas son seguras para hilos? ¿Qué sucede cuando dos hilos ejecutan CAS al mismo tiempo? ¿no es una condición de carrera? – hardik

+1

@Hardik no existe una condición de carrera debido a que la relación 'pasa antes' (http://en.wikipedia.org/wiki/Hacia antes) se impone por las operaciones atómicas y, por lo tanto, la seguridad resultante de la secuencia. –

8

Pre-incremento en int es no hilo de seguridad, utilizar AtomicInteger que es-lock libre:

AtomicInteger carsComplete = new AtomicInteger(); 

//... 

switch(carsComplete.incrementAndGet()) 

BTW el código de abajo es no hilo seguro también. ¿Puedes decir por qué?

carsComplete.incrementAndGet(); 
switch(carsComplete.get()) 
+1

Como el subproceso 1 puede alcanzar la instrucción switch, ceda el subproceso 2, que se ejecuta incrementAndGet incrementando así el backing store para carsComplete, momento en el que el subproceso 1 se ejecuta de nuevo con el almacenamiento de reserva dos veces, una por cada subproceso. –

+0

Exactamente, sin embargo no hay premio esta vez ;-). –

5

Igual que en C++ el operador ++ no es atómica.

En realidad, es más de 1 instrucción se ejecuta bajo el capó (no se deje engañar por ver sólo un simple ++i, es load/add/store) y puesto que hay más de 1 instrucción involucrados sin sincronización que pueden tener diferentes intercalaciones con resultados incorrectos.

Si necesita incrent la carsComplete de una manera segura para los subprocesos se puede utilizar constructo de java AtomicInteger o podría sincronizar todo el método

1

pregunta es “es el hilo operador de incremento previo a salvo?”

Ans : No porque ? debido a la cantidad de instrucciones involucradas. Atomic significa operación única, aquí se deben realizar operaciones de carga/adición/almacenamiento. Entonces no es una operación atómica.

Same for post increment. 
Cuestiones relacionadas