2012-02-21 19 views
9
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(); 
    } 
} 

quando ho eseguito questo programma sto ottenendo l'output comeDue thread possono accedere contemporaneamente a un metodo sincronizzato?

Alphonse: Gaston si è piegato a me! Gaston: Alphonse mi ha inchinato!

Quindi due thread possono accedere contemporaneamente a un metodo sincronizzato?

+0

possibile duplicato di [Cercando di avvolgere il mio cervello su come si blocca il thread] (http://stackoverflow.com/questions/749641/trying-to-wrap-my-wee-brain-around-how-threads-deadlock) –

risposta

7

Due thread possono accedere contemporaneamente a un metodo sincronizzato?

I metodi di istanza (come il tuo esempio) sono sincronizzati sull'oggetto che li contiene. In questo caso, quando si chiama alphonse.bow(...) si sta bloccando l'oggetto alphonse. gaston.bow(...) blocchi gaston.

Ci sono un paio di modi in cui è possibile ottenere più istanze di un oggetto per bloccare lo stesso oggetto.

  • Si potrebbe fare il metodo sia static e synchronized nel qual caso avrebbero bloccare sull'oggetto classe stessa. C'è solo uno di questi oggetti per il caricatore di classi.

    public static synchronized void bow(Friend bower) { 
    
  • Entrambi potevano bloccare un oggetto statico definito. Qualcosa di simile:

    private static final Object lockObject = new Object(); 
    ... 
    public void bow(Friend bower) { 
        synchronized (lockObject) { 
         .... 
        } 
    } 
    
  • Oppure si potrebbe passare l'oggetto da bloccare se non si desidera renderlo statico.

L'output potrebbe essere simile al seguente:

  1. il gaston filo (eventualmente) inizia prima e chiede bow(alphonse)
  2. questo blocca i gaston oggetto e uscite: Gaston: Alphonse has bowed to me!
  3. chiama alphonse.bowBack(this).
  4. questa chiamata blocca i alphonse oggetto e uscite: Alphonse: Gaston has bowed back to me!
  5. alphonse.bowBack(this) uscite, sbloccando l'oggetto alphonse.
  6. gaston.bow(alphonse) uscite, sblocco dell'oggetto gaston.
  7. quindi esce il thread gaston.
  8. il alphonse filo (eventualmente) inizia dopo e chiede bow(gaston)
  9. questo blocca l'oggetto e uscite alphonse: Alphonse: Gaston has bowed to me!
  10. chiama gaston.bowBack(this).
  11. questa chiamata blocca i gaston oggetto e uscite: Gaston: Alphonse has bowed back to me!
  12. gaston.bowBack(this) uscite, sbloccando l'oggetto gaston.
  13. alphonse.bow(gaston) uscite, sblocco dell'oggetto alphonse.

Questo potrebbe accadere in un numero di ordini diversi. Il thread alphonse potrebbe essere eseguito per primo anche se il metodo start() viene chiamato in un secondo momento. L'unica cosa di cui le serrature ti evitano è la chiamata di alphonse.bow(...) se alphonse.bowBack(...) è attualmente in esecuzione. Come sottolineato @ user988052, poiché ogni thread blocca il proprio oggetto e quindi tenta di bloccare l'altro, è possibile ottenere facilmente un deadlock.

+0

ok..ma qualche volta quando eseguo questo programma ottengo l'output come: Gaston: Alphonse mi ha inchinato! Alphonse: Gaston mi ha fatto un inchino! Alphonse: Gaston si è inchinato a me! Gaston: Alphonse mi ha fatto un inchino! Quindi .. come che succede..intendo che questo programma dovrebbe bloccare come nel tutorial .. – harish

+0

@harish: succede perché il primo thread potrebbe aver terminato il suo lavoro prima che il secondo thread sia iniziato. Per questo motivo, per creare con certezza (almeno con una probabilità molto probabile) un deadlock, devi istanziare molti thread (vedi la mia risposta). – TacticalCoder

+0

@ user988052 l'hai capito..grazie .. – harish

10

Quindi due thread possono accedere contemporaneamente a un metodo sincronizzato?

Sì e no:

  • Sì, se il metodo viene chiamato su diversi istanze della classe.

  • No, due thread non possono chiamare simultaneamente i metodi sincronizzati su la stessa istanza della classe. Questo è il caso anche se i due thread chiamano metodi diversi (purché l'istanza sia la stessa).

+2

Nota: se un metodo sincronizzato chiama un altro metodo sincronizzato sullo stesso oggetto, un thread può essere contemporaneamente in due metodi sincronizzati sullo stesso oggetto. –

+0

@aix: puoi modificare la tua risposta per indicare che la sincronizzazione viene eseguita sulla classe. Anche il tuo primo punto elenco non è corretto per la sincronizzazione della classe. – Perception

+0

@Perception: Non sono sicuro che io segua. Poiché i metodi non sono 'static', la sincronizzazione blocca l'istanza, non la classe. Potresti spiegare cosa intendi? – NPE

0

Con la parola chiave sincronizzata si prende un blocco su un'istanza per un metodo di istanza o su una classe per un metodo statico. Quindi qui garantisci che al massimo un thread esegue bow o bowBack su una data istanza in un dato momento (se un thread esegue l'arco nessun altro thread può eseguire bowBack perché entrambi i metodi si sincronizzano sullo stesso blocco) ...

One altro commento: dato che i blocchi sono rientranti una volta che un thread ha acquisito un blocco, può entrare in altri metodi di sincronizzazione sullo stesso blocco.

1

Come descritto nello Deadlock Tutorialsche è dove questo codice proviene da questo codice di solito blocca.

Quando Deadlock è in esecuzione, è estremamente probabile che entrambi i thread si blocchino quando tentano di richiamare bowBack. Nessun blocco finirà mai, perché ogni thread sta aspettando che l'altro esca dall'arco.

2

non ho controllato il codice in dettaglio, ma credo che riconosco il tipico esempio su come creare una situazione di stallo.

Tuttavia non dovresti chiamarlo solo una volta per provare a creare il punto morto.

creare thread in un ciclo e c'è una probabilità molto alta avrai la tua situazione di stallo:

for (int i = 0; i < 1000; i++) { 
    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(); 
} 

Nota che non sarà stallo le discussioni che 2000: solo alcuni di loro saranno un punto morto. Puoi verificarlo prendendo un thread del tuo programma/JVM.

Problemi correlati