uso titledborder poner layouts crear con borde java deadlock

poner - titledborder java



Punto muerto: ¿cómo sucede en este ejemplo? (4)

alguien puede explicar:

  1. ¿Por qué tenemos un punto muerto?
  2. ¿Cómo puede Gaston entrar en la función de arco antes de que Alphonse salga de esa función? (debería regresar de la función bowBack() para salir de la función bow() - o)?

Esta es la salida que recibo, ¡y luego el programa se atasca!

Alphonse: ¡Gaston me ha hecho una reverencia!

Gaston: Alphonse me ha hecho una reverencia!

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(); } }


El bloque / método sincronizado se sincroniza con this , es decir, la instancia de objeto al que se llama el bloque / método. (Para static "instancia de objeto" static se debe reemplazar con "instancia de clase".)

Es decir, tus 2 objetos se sincronizan a sí mismos, no a un objeto común.

Intenta algo como esto:

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 (getClass()) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } } public void bowBack(Friend bower) { synchronized (getClass()) { 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(); } }


En primer lugar, el uso de sincronizado es incorrecto. El tutorial oráculo dice muy bien:

Primero, no es posible intercalar dos invocaciones de métodos sincronizados en el mismo objeto.

Como se explica en la otra respuesta: el código que se muestra en el ejemplo no utiliza un "bloqueo común" (los métodos sincronizados en dos objetos diferentes no afectan la "otra" llamada de método).

Más allá de eso: tan pronto como elimines esas llamadas de System.out.format() , tu programa puede (lo más a menudo posible) no tener un punto muerto.

O: coloque un println() en su main antes de comenzar los subprocesos; de nuevo, el programa no se bloqueará.

En otras palabras: imprimir en la consola consume mucho tiempo. Por lo tanto, esto afecta el tiempo de tus hilos dramáticamente! Lo que sucede aquí es que la mayor parte del tiempo se dedica a las acciones de salida de la consola. Vea here una pregunta similar que incluso usa los mismos nombres ;-)


Lo que pasa en tu ejemplo:

  1. El hilo Alphonse está adquiriendo el bloqueo a Alphonse entrando en la función bow .

  2. Hilo Gaston está adquiriendo el bloqueo a Gaston entrando en la función de bow .

  3. Thread Alphonse está solicitando el bloqueo a Gaston para ingresar a la función bowBack pero ese bloqueo está actualmente en manos de Thread Gaston, por lo que Alphonse se ve obligado a esperar.

  4. Thread Gaston está solicitando el bloqueo a Alphonse para ingresar a la función bowBack pero ese bloqueo está actualmente en manos de Thread Alphonse, por lo que Gaston se ve obligado a esperar.

Punto muerto.

Por qué sucede esto:

Una función synchronized es el azúcar sintáctico para synchronized(this) { ... } Por lo que la clase anterior también podría escribirse así:

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()); } }

this en este ejemplo es, sin embargo, la instancia de la clase, por lo que cada instancia tiene su bloqueo individual. Si desea bloquear el mismo objeto en todas las instancias de una clase, necesita bloquear un objeto estático como este:

protected static final Object STATIC_LOCK = new Object(); public void bow(Friend bower) { synchronized (STATIC_LOCK) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } } public void bowBack(Friend bower) { synchronized (STATIC_LOCK) { System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName()); } }

Dado que este objeto LOCK es estático, ambos subprocesos ahora se bloquearán en el mismo objeto y, por lo tanto, se bloquearán entre sí correctamente. Observe la palabra clave final que se recomienda encarecidamente en este caso, porque de lo contrario, los bloqueos sincronizados podrían cambiar durante la ejecución (debido a errores o descuidos en su código), lo que lo pondría de nuevo en la situación de bloqueo por el mismo motivo anterior. .


Tema 1: la instancia de alphonse se bloquea desde alphonse.bow(gaston); que imprime una línea y luego llama a gaston.bowBack() (pero gaston está bloqueado en el subproceso 2 debido a una instancia de bow() sincronizada que se muestra a continuación)

Tema 2: la instancia de gaston se bloquea de gaston.bow(alphonse); que imprime una línea y luego llama a alphonse.bowBack() (pero alphonse está bloqueado de Thread 1 debido a una instancia de bow() sincronizada).

Así que ambos esperan el lanzamiento y no pueden salir del método bow() , por lo tanto, el punto muerto