Cita de: ~ Yoya ~ en 19 Enero 2014, 22:53 PM
FixedCódigo (java,13) [Seleccionar]
public class Hilo extends Thread {
private int tipoHilo;
private static Integer n = new Integer(0);
private int nVueltas;
public Hilo(int nVueltas, int tipoHilo) {
this.nVueltas = nVueltas;
this.tipoHilo = tipoHilo;
}
public void run() {
synchronized (n) {
switch (tipoHilo) {
case 0:
for (int i = 0; i < nVueltas; i++)
n = n + 1;
;
break;
case 1:
for (int i = 0; i < nVueltas; i++)
n = n - 1;
;
break;
}
}
}
public static void main(String[] args) throws Exception {
Hilo p = new Hilo(10000, 0);
Hilo q = new Hilo(10000, 1);
p.start();
q.start();
p.join();
q.join();
System.out.println(n);
}
}
La razón porque al principio no funcionaba es porque habías puesto el keyword synchronized dentro del un loop. Cuando se iniciaba un ciclo en el loop, uno de los 2 thread tomaba el lock y el otro esperaba a que liberen el lock.
El problema esta en que el lock se libera cuando termina cada ciclo (son 10,000 ciclos como haz indicado), y puede pasar 2 cosas:
- El thread que habia tomado el lock toma el lock de nuevo
- El thread que estaba esperando que liberen el lock toma el lock.
Por lo tanto, en un momento la variable se puede incrementar y en el siguiente puede que disminuya, y en el siguiente puede incrementarse o disminuirse, y asi.
Ahora al poner el keyword al inicio de todo el metodo, el lock se libera solo cuando el metodo se termine de ejecutar, y cuando se termina de ejecutar, entonce el segundo thread puede tomar el lock ya que se ha liberado.
Saludos.
Que? no es como dices, porque tal como tu comentas se ejecutaria todo de manera secuencial, mientras que lo que interesa es el paralelismo lo maximo posible para incrementar el rendimiento.
Poner el synchronized dentro del bucle no tiene problema, ya que la sección critica es el contador (la variable n).
El problema del codigo que puse, es que si utilizas un objeto como cerrojo y lo usas, este se modifica y sus propiedades como cerrojo se pierden y se produce el dichoso entrelazado.
Como dije en el primer comentario, si en vez de poner el cerrojo el objeto n de la clase integer ponemos cualquier otro objeto y este no se modifica en ningun momento, el codigo funcionara perfectamente y no existira entrelazado.
Por cierto, lo de poner el synchronized en el switch es una burrada enorme ... porque la gracia de este codigo es ejecutarlo de forma concurrente mientras que tu manera le quita toda la concurrencia posible...