threads - java y sincronización
synchronized class in java (4)
Me estoy preparando para el examen SCJP y estoy teniendo problemas para comprender completamente la sincronización. En la línea 6, he leído que el hilo que se ejecuta en main necesita un bloqueo en ''b''. ¿Por qué necesita un bloqueo en este objeto? Según entiendo, ¿un bloque de código sincronizado es un área protegida en la que solo puede haber un hilo en cualquier momento? Moviéndose, el hilo en main libera este bloqueo y espera a que el hilo en ''b complete su método de ejecución. El hilo en ''b'' está destinado a notificar al hilo en el principal que se ha completado. Sin embargo, no parece que esté notificando ningún hilo específico aquí. Este ejemplo es del libro SCJP de Sierra y Bates. Cualquier luz que se pueda arrojar sobre esto sería gratamente apreciada. Gracias
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
**synchronized(b) { //line 6**
try {
System.out.println("Waiting for b to complete...");
b.wait();
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
}
}
}
}
class ThreadB extends Thread {
int total;
public void run() {
System.out.println("K");
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
notify();
}
}
}
En la línea 6, he leído que el hilo que se ejecuta en main necesita un bloqueo en ''b''. ¿Por qué necesita un bloqueo en este objeto?
Porque eso es lo que hace esa línea. Adquiere ese recurso. Otro subproceso puede obtener otro bloque sincronizado, pero ningún otro subproceso puede adquirir un bloqueo en ese objeto.
no parece que esté notificando ningún hilo específico aquí.
Esto es verdad. El programa no tiene idea de qué hilo será notificado o incluso si se notificará algún hilo. Usted, como desarrollador, puede concluir que hay un hilo en particular que será notificado, tal vez porque es el único hilo que espera ().
Ambos hilos se sincronizan en el mismo Object
aquí, es decir, b
. main()
primero adquiere el bloqueo, pero luego llama a b.wait()
, que libera el bloqueo y espera a que alguien llame a notify()
en b
.
Eso significa que cuando el método run()
, que en este caso se llama en b
, llama a notify()
, esto volverá a activar el método main()
.
Entonces, que el bloqueo se adquiera en b
no es realmente importante aquí, la parte importante es que ambos hilos adquieren el mismo bloqueo, o la cooperación wait()/notify()
no funcionará.
El código utiliza el mecanismo wait()
para garantizar que el result
sea computado por otro ThreadB
.
Para esperar en el objeto que necesita para obtener el bloqueo en ese objeto que es donde entra la line 6
, synchronized (b)
a la imagen.
Una mejor forma de ejecutar el mismo programa es usar el método Thread # join () .
public final void join()
throws InterruptedException
Waits for this thread to die.
Este es un caso muy especial y no harías eso.
Lo que sucede es que el hilo main
sincroniza en el objeto ThreadB
y wait
.
Cuando ThreadB
termina, se ThreadB
una notify
y, como resultado, se reactiva y continúa main
.
Pero este no es el código que normalmente escribiría, es decir, usar objetos Thread
para la synchronization
.
Para ver cómo es la esquina del caso, simplemente elimine la notify
del bucle de ThreadB
.
El código seguirá funcionando debido a que se sincroniza en un objeto Thread
y la implementación genera una notificación después de que un Thread
haya finalizado.
El comportamiento es contrario a la intuición y propenso a errores.