2009-07-09 8 views
11

Un po 'di aiuto per favore, considera il bit di codice qui sotto.Blocco rientrante

public class Widget { 
    public synchronized void doSomething() { 
     ... 
    } 
} 

public class LoggingWidget extends Widget { 
    public synchronized void doSomething() { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

Ho letto che quando viene chiamata doSomething() in LoggingWidget, JVM tenterà di acquisire un blocco su LoggingWidget prima e poi su Widget.

Sono curioso di sapere il motivo. È perché la JVM sa che DoSomething() ha una chiamata a super.doSomething() o perché chiamare un metodo di sottoclasse acquisirà sempre un blocco anche sulla superclasse.

Acclamazioni

+0

Dovresti postare un riferimento a dove leggi questo perché non è vero :-) –

+0

Grazie davvero per il tuo aiuto. Ho frainteso la spiegazione del blocco rientrante.Dopo aver letto la tua spiegazione, sono tornato alla fonte (un estratto dal libro Concurrency in pratica) e ha senso ora. – CaptainHastings

risposta

9

vi sbagliate - le serrature sono ottenuti a livello diesempio. C'è solo un blocco nel tuo esempio perché non v'è una sola istanza creata quando dici:

Widget w = new LoggingWidget 

È possibile visualizzare le serrature (noto anche come monitor, mutex o semafori) come individualmente " allegato "a ogni istanza di oggetto nello JVM.

Se si dispone di un altro metodo synchronized nella sottoclasse LoggingWidget, si vedrà che questo è vero. Non sarebbe possibile chiamare questo (nuovo) metodo e il metodo doSomething allo stesso tempo [con thread diversi sullo stesso oggetto].

Ciò vale anche per un altro metodo synchronized nella superclasse (vale a dire che non viene influenzato in alcun modo dai metodi sovrascritti).

1

C'è solo un'istanza per ottenere il blocco, l'istanza di LoggingWidget, non c'è mai un'istanza effettiva di Widget.

Il blocco si ottiene quando si chiama LoggingWidget.doSomething() e come già si ha il blocco quando si chiama super.doSomething() tale metodo viene eseguito normalmente.

+0

Grazie Nick, ha senso. – CaptainHastings

5
public synchronized void doSomething() { 
    System.out.println(toString() + ": calling doSomething"); 
    super.doSomething(); 
} 

è lo stesso:

public void doSomething() { 
    synchronized (this) { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

Stai blocco nell'istanza, non la classe. Quindi, quando viene chiamato super.doSomething(), hai già quell'istanza bloccata.

+0

Grazie, mentre la canzone va, posso vedere chiaramente ora ... – CaptainHastings

0

Reentrancy funziona acquistando prima la serratura. Quando un thread acquisisce il blocco è noto in jvm. Quando si immette un blocco di codice che è sincronizzato con il thread che è attualmente in possesso di un blocco, è consentito continuare senza ri-acquisire il blocco. Il jvm aumenta quindi il contatore di ogni azione rientrante, diminuendo ulteriormente quando si esce da quel blocco finché il conteggio non è zero. Quando il conteggio è zero, il blocco viene rilasciato.

0

B.Goetz - "Concorrenza di JJava in pratica" se i blocchi intrinseci non erano rientranti, la chiamata a super.doSomething non sarebbe mai stata in grado di acquisire il blocco perché sarebbe considerato già tenuto, e il thread sarebbe permanentemente bloccato in attesa per una serratura che non può mai acquisire. La rientranza ci salva da situazioni di stallo in situazioni come questa.

Problemi correlati