starvation lock example java concurrency deadlock

lock - Pregunta sobre la situación de punto muerto en Java



synchronization java (6)

Los bloqueos se realizan en objetos Java, no en Java. Entonces, cuando se utiliza sincronización en un método, bloquea el objeto "this". En el caso de un método estático, bloquea el objeto de clase.

Puede especificar explícitamente el objeto del monitor utilizando synchronized ( object ) { }

Estoy aprendiendo acerca de los interbloqueos en Java, y hay este código de muestra del tutorial oficial de Sun:

Alphonse y Gaston son amigos y grandes creyentes en cortesía. Una regla estricta de cortesía es que cuando te inclines ante un amigo, debes permanecer encorvado hasta que tu amigo tenga la oportunidad de devolver el arco. Desafortunadamente, esta regla no explica la posibilidad de que dos amigos se dobleguen al mismo tiempo.

public class Deadlock { static class Friend { private final String name; public Friend(String name) { this.name = name; } public String getName() { return this.name; } public synchronized void bow(Friend bower) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } public synchronized void bowBack(Friend bower) { System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName()); } } public static void main(String[] args) { final Friend alphonse = new Friend("Alphonse"); final Friend gaston = new Friend("Gaston"); new Thread(new Runnable() { public void run() { alphonse.bow(gaston); } }).start(); new Thread(new Runnable() { public void run() { gaston.bow(alphonse); } }).start(); } }

Aquí está la explicación de Sun:

Cuando se ejecuta el Interbloqueo, es muy probable que ambos subprocesos se bloqueen cuando intentan invocar la Devolución de Arco. Ninguno de los bloques terminará nunca, porque cada hilo está esperando que el otro salga del arco.

No parece seguirlo. Cuando se ejecuta alphonse.bow (gaston), el método de proa se bloquea. Así que ahora primero se imprimirá "¡Gaston se inclinó ante mí!". Luego continuará y llamará a BowBack y también bloqueará BowBack. ¿Cómo puede esto causar un punto muerto? ¿Estoy entendiendo mal qué sucede cuando se llama a un método sincronizado?

Si alguien me puede dar una explicación fácil, gracias.


Para agregar a simonn, et al.,

Si desea visualizar esto, compile y ejecute el programa y genere un volcado de subprocesos del programa en ejecución. Puede hacerlo escribiendo Ctrl - Break en una consola de Windows o emitiendo un kill -QUIT [pid] a un sistema * nix. Lo que esto le proporcionará es una lista de todos los subprocesos que se ejecutan en su sistema y dónde están en ejecución o en espera, así como también los monitores que los subprocesos están bloqueando o esperando para cerrarse.

Si cambia sus nombres de subprocesos en sus constructores, le será más fácil encontrarlos en el volcado completo de subprocesos:

new Thread(new Runnable() { public void run() { alphonse.bow(gaston); } }, "Alphonse").start(); new Thread(new Runnable() { public void run() { gaston.bow(alphonse); } }, "Gaston").start();


Tendría que verificarlo dos veces, pero creo que un método sincronizado se bloquea en el objeto de la clase, por lo que bloquea otros métodos sincronizados en la misma clase.

Creo que se bloquea en el objeto de la clase en sí, por lo que incluso bloquea diferentes instancias.

Editar para agregar:

Eche un vistazo a esta parte de la especificación del lenguaje java

Cada método de arco agarra su propio monitor de objetos. Ambos intentan llamar al arco del otro objeto y bloquean esperando al otro monitor.


Un punto importante a tener en cuenta es que no se trata de métodos que están bloqueados sino de instancias de objetos .

Cuando llamas a alphonse.bow(gaston) , intenta obtener el bloqueo de alphonse . Una vez que tiene el bloqueo, imprime un mensaje y luego llama a gaston.bowBack(alphonse) . En este punto, intenta adquirir el bloqueo de gaston . Una vez que tiene el bloqueo, imprime un mensaje, luego libera el bloqueo y finalmente se libera el bloqueo de alphonse .

En punto muerto, los bloqueos se adquieren en un orden tal que no hay forma de que ninguno de los subprocesos avance.

  • Subproceso 1: adquiere bloqueo en alphonse
  • Subproceso 2: adquiere bloqueo en gaston
  • Tema 1: imprime el mensaje
  • Subproceso 1: intenta obtener bloqueo en gaston : no se puede, porque el Tema 2 ya lo tiene.
  • Tema 2: imprime el mensaje
  • Subproceso 2: intenta obtener el bloqueo en alphonse : no se puede, porque el subproceso 1 ya lo tiene.

sincronizado en una definición de método es una forma abreviada de sincronización en el objeto (esto). En esencia, esto significa que bow () y bowBack () no se pueden invocar mutuamente en el mismo objeto Friend.

Ahora, si ambos amigos entran en bow (), ninguno de ellos podrá invocar el método bowBack () de los demás.


alphonse y gaston son dos objetos diferentes. Cada objeto tiene un monitor intrínseco (cerradura) que está asociado con él.

Podría suceder así:

Alphonse es creado. Su monitor de objetos es 1.

Gaston es creado. Su monitor de objetos es 2.

alphonse.bow (gaston); Alphonse ahora posee la cerradura # 1

gaston.bow (alphonse); Gaston ahora posee la cerradura # 2

alphonse llama a BowBack sobre gaston y está esperando el bloqueo # 2. Gaston llama a BowBack sobre alphonse y está esperando el bloqueo # 1.

¿Tener sentido? El uso de la palabra clave sincronizada bloquea las instancias que supervisan durante la duración del método. El ejemplo podría reescribirse de la siguiente manera:

public class Deadlock { static class Friend { private final String name; public Friend(String name) { this.name = name; } public String getName() { return this.name; } public void bow(Friend bower) { synchronized(this) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } } public void bowBack(Friend bower) { synchronized(this) { System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName()); } } } }