2009-04-14 28 views
11

En primer lugar, here's a sample:¿Cómo funciona el trabajo sincronizado en Java

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

Lo que no entiendo es cómo se produce la obstrucción. La función principal inicia dos hilos que cada uno comienza sus propios arcos.

¿Qué es exactamente el bloqueo "sincronizado"? La misma función que se ejecuta para el mismo objeto (como originalmente pensé)? La misma función para todos los objetos de la misma clase? Todas las funciones sincronizadas para el mismo objeto? Todas las funciones sincronizadas para todos los objetos de la misma clase?

Ayúdame aquí.

Respuesta

22

En Java, cada Object proporciona la capacidad de un subproceso a synchronize, o bloqueo, en él. Cuando un método está sincronizado, el método usa su instancia de objeto como el bloqueo. En su ejemplo, los métodos bow y bowBack son ambos synchronized, y ambos están en la misma clase Friend. Esto significa que cualquier Thread que ejecute estos métodos se sincronizará en una instancia Friend como su bloqueo.

una secuencia de eventos que causarán un callejón sin salida es:

  1. el primer hilo comenzó llamadas alphonse.bow(gaston), que es synchronized en el objeto alphonseFriend. Esto significa que el subproceso debe adquirir el bloqueo de este objeto.
  2. El segundo subproceso inició llamadas gaston.bow(alphonse), que es synchronized en el objeto gastonFriend. Esto significa que el subproceso debe adquirir el bloqueo de este objeto.
  3. El primer hilo iniciado ahora llama al bowback y espera a que se libere el bloqueo en gaston.
  4. El segundo hilo iniciado ahora llama a bowback y espera a que se libere el bloqueo en alphonse.

Para mostrar la secuencia de eventos con mucho más detalle:

  1. main() comienza a ejecutar en el principal Therad (lo llaman hilo # 1), creando dos Friend casos. Hasta aquí todo bien.
  2. El subproceso principal inicia su primer subproceso nuevo (llámalo Subproceso # 2) con el código new Thread(new Runnable() { .... El subproceso n. ° 2 llama al alphonse.bow(gaston), que es synchronized en el objeto alphonseFriend. El subproceso n. ° 2 adquiere así el "bloqueo" para el objeto alphonse e ingresa el método bow.
  3. Aquí se produce un segmento de tiempo y el subproceso original tiene la posibilidad de hacer más procesamiento.
  4. El subproceso principal inicia un segundo subproceso nuevo (llámalo subproceso n. ° 3), al igual que el primero. El hilo # 3 llama al gaston.bow(alphonse), que está sincronizado en el objeto gastonFriend. Como nadie ha adquirido todavía el "candado" para la instancia de objeto gaston, el subproceso n. ° 3 adquiere con éxito este candado e ingresa el método bow.
  5. Aquí se produce un corte de tiempo y el subproceso n. ° 2 tiene la posibilidad de hacer más procesamiento.
  6. El subproceso # 2 ahora llama a bower.bowBack(this); con bower siendo una referencia a la instancia de gaston. Este es el equivalente lógico de una llamada de gaston.bowBack(alphonse). Por lo tanto, este método es synchronized en la instancia gaston. El bloqueo para este objeto ya ha sido adquirido y está retenido por otro subproceso (subproceso n. ° 3). Por lo tanto, el subproceso n. ° 2 tiene que esperar a que se libere el bloqueo en gaston. El subproceso se pone en estado de espera, permitiendo que el subproceso n. ° 3 se ejecute más.
  7. El subproceso n. ° 3 ahora llama a bowback, que en este caso es lógicamente el mismo que la llamada alphonse.bowBack(gaston). Para hacer esto, necesita adquirir el candado para la instancia alphonse, pero este bloqueo lo retiene el Subproceso # 2. Este hilo se pone ahora en estado de espera.

Y ahora se encuentra en una posición en la que ninguno de los hilos se puede ejecutar. Tanto el Subproceso # 2 como el Subproceso # 3 están esperando que se libere un bloqueo. Pero ninguno de los bloqueos puede liberarse sin que el hilo avance. Pero ninguno de los hilos puede progresar sin que se suelte un bloqueo.

Así: ¡Interbloqueo!

Los bloqueos suelen depender de una secuencia específica de eventos que se producen, lo que puede dificultar la depuración ya que pueden ser difíciles de reproducir.

+2

Oh ok. Entonces la cerradura pertenece a todo el objeto. No sé por qué pensé que solo eran llamadas al mismo método sincronizado para un objeto dado que están bloqueadas. Supongo que eso responde mi pregunta. –

+0

El objeto no realiza sincronización/bloqueo, sino que es el hilo. –

+1

En realidad, he hablado específicamente sobre el hilo que adquiere el bloqueo, pero veo que parte de mi lenguaje es inexacto. Lo dejaré más claro. – Eddie

2

Synchronized has two effects:

  • primer lugar, no es posible que dos invocaciones de métodos sincronizados en el mismo objeto para intercalar. Cuando un hilo está ejecutando un método sincronizado para un objeto, todos los otros hilos que invocan métodos sincronizados para el mismo bloque de objetos (suspenden la ejecución) hasta que el primer hilo termina con el objeto.
  • En segundo lugar, cuando sale un método sincronizado, establece automáticamente una relación de pasar antes con cualquier invocación posterior de un método sincronizado para el mismo objeto. Esto garantiza que los cambios en el estado del objeto sean visibles para todos los hilos.

En resumen, bloquea las invocaciones de métodos sincronizados en el mismo objeto.

2

Todas las funciones sincronizadas para el mismo objeto. Marcar un método "sincronizado" es muy similar a poner un "bloque sincronizado (esto) {" alrededor de todo el contenido del método. La razón por la que no digo "idéntico" es porque no sé de pasada si el compilador emite el mismo bytecode o no, pero AFAIK el efecto de tiempo de ejecución definido es el mismo.

El punto muerto es una clásica inversión de bloqueo. Un hilo bloquea alphonse. Luego (o al mismo tiempo en un sistema multi-core) el otro hilo bloquea gaston. Esta parte requiere que la programación de los hilos simplemente se entrelaza en los puntos correctos.

Cada hilo (en cualquier orden o simultáneamente) intenta adquirir un bloqueo que ya está en el otro hilo y, por lo tanto, cada hilo queda en reposo. Ninguno se despertará hasta que el otro libere su bloqueo, pero ninguno liberará su bloqueo hasta que se despierte (o se termine).

2

El método sincronizado es la misma que encierra todos los código de métodos en un bloque

synchronized(this) { 
    /// code here ... 
} 

.

Para una instancia de objeto determinada o, sólo un hilo a la vez puede ejecutar cualquier sincronizada (o) bloque. Cualquier otro hilo que intente se lamentará, hasta que el hilo que ejecuta ese bloque (tiene el bloqueo sincronizado en él) sale de ese bloque (abandona el bloqueo).

En su caso, el punto muerto ocurre cuando Alphonse comienza a inclinarse en el hilo 1, ingresando así al bloque sincronizado. El subproceso 1 luego se intercambia por el sistema, por lo que el subproceso 2 puede comenzar y hacer que Gaston se incline. Pero Gaston no puede retroceder todavía, porque se está sincronizando con Alphonse, y el Tema 1 ya tiene ese bloqueo. Esperará que el Tema 1 abandone ese bloque. El sistema intercambiará de nuevo el subproceso 1, que intentará hacer que Alphonse se incline hacia atrás. Excepto que no puede hacerlo porque el Tema 2 tiene el bloqueo sincronizado en Gaston. Ambos hilos están atascados, esperando que el otro termine de inclinarse antes de poder inclinarse hacia atrás ...

Cuestiones relacionadas