2013-05-12 7 views
33

Reentrancy indica che i blocchi vengono acquisiti su una base per-thread piuttosto che per invocazione.'Reentrancy' in java

Poiché un blocco intrinseco è trattenuto da un thread, non significa che un thread eseguito una volta equivale a una base di invocazione?

Grazie, sembra dire che: in un thread, se ho un blocco lockA quando la funzione di processo doA che chiamata di funzione doB, e doB hanno bisogno anche di un blocco lockA, allora ci wil essere una rientranza. In Java, questo fenomeno è acquisito per thread, quindi non ho bisogno di considerare deadlock?

+0

Immaginate se entrando un metodo serrature oggetto X, e mentre in tale metodo si chiama il metodo stesso (direttamente o ulteriormente nello stack di chiamate) e il blocco oggetto X di nuovo. Che succede?Aspetti il ​​blocco che hai già in mano, o è consapevole che il thread che lo trattiene è anche il thread che lo chiama di nuovo e gli consente di passare? Si chiama re-entrancy: si entra nello stesso metodo in cui eri già in precedenza. – Patashu

+1

Sì, i blocchi sincronizzati e i blocchi in Java sono rientranti, quindi una volta che thread foo ha una barra di blocco, può tranquillamente chiamare metodi che bloccano anche la barra senza dover prima sbloccarla. – Patashu

+0

È ancora necessario considerare deadlock, può verificarsi un deadlock quando due thread si attendono reciprocamente. – rubixibuc

risposta

52

Rientranza significa che i blocchi vengono acquisiti su un filo per-piuttosto che ogni singola chiamata.

Questa è una definizione fuorviante. È vero (una specie di), ma manca il vero punto.

Reentrancy significa (in generale terminologia CS/IT) che si fa qualcosa, e mentre lo si sta ancora facendo, lo si fa di nuovo. Nel caso di serrature vuol dire fare qualcosa di simile su un singolo thread:

  1. acquisire un blocco su "foo".
  2. Fare qualcosa
  3. Acquisire un blocco su "foo". Si noti che non abbiamo rilasciato il blocco che abbiamo precedentemente acquisito.
  4. ...
  5. serratura uscita su "foo"
  6. ...
  7. serratura uscita su "foo"

Con una serratura rientrante/meccanismo di bloccaggio, il tentativo di acquisire la stessa il blocco avrà successo e incrementerà un contatore interno appartenente al blocco. Il blocco verrà rilasciato solo quando il supporto corrente della serratura lo ha rilasciato due volte.

Ecco un esempio in Java utilizzando primitive oggetto serrature/monitor ... che sono rientrante:

Object lock = new Object(); 
... 
synchronized (lock) { 
    ... 
    doSomething(lock, ...) 
    ... 
} 

public void doSomething(Object lock, ...) { 
    synchronized (lock) { 
     ... 
    } 
} 

L'alternativa è rientrante frenafiletti non rientrante, dove sarebbe un errore per un thread tenti per acquisire un lucchetto che già detiene.

Il vantaggio di utilizzare i blocchi di rientro è che non devi preoccuparti della possibilità di non riuscire a causa dell'acquisizione accidentale di un blocco già in tuo possesso. Lo svantaggio è che non si può presumere che nulla che chiami cambierà lo stato delle variabili che il blocco è progettato per proteggere. Tuttavia, di solito non è un problema.I lucchetti vengono generalmente utilizzati per proteggere dalle modifiche concomitanti dello stato effettuate da altri thread.


Quindi non ho bisogno di prendere in considerazione situazioni di stallo?

Sì.

Un filo non si bloccherà contro se stesso (se il blocco è rientrante). Tuttavia, potresti ottenere un deadlock se ci sono altri thread che potrebbero avere un blocco sull'oggetto che stai cercando di bloccare.

+0

Poiché un thread è una volta in esecuzione, come potrei farlo mentre lo faccio ancora, quindi rifarlo? – znlyj

+1

Vedere l'esempio codice Java che ho appena aggiunto. –

+0

Sì, grazie. – znlyj

1

Ciò significa che una volta che un thread ha un blocco, può entrare nella sezione di codice bloccata tutte le volte che è necessario. Quindi se hai una sezione di codice sincronizzata come un metodo, solo il thread che ha raggiunto il lock può chiamare quel metodo, ma può chiamare quel metodo quante volte vuole, incluso qualsiasi altro codice detenuto dallo stesso lock. Questo è importante se si dispone di un metodo che chiama un altro metodo ed entrambi sono sincronizzati dallo stesso blocco. Se questo non fosse il caso. La seconda chiamata al metodo bloccherebbe. Si applicherebbe anche alle chiamate al metodo ricorsivo.

public void methodA() 
{ 
    // other code 
    synchronized(this) 
    { 
      methodB(); 
    } 
} 

public void methodB() 
{ 
    // other code 
    syncrhonized(this) 
    { 
      // it can still enter this code  
    } 

} 
13

Immaginate qualcosa di simile:

function A(): 
    lock (X) 
     B() 
    unlock (X) 

function B(): 
    A() 

Ora noi chiamiamo A. La verifica quanto segue:

  • Entriamo in un, blocco X
  • Entriamo B
  • entriamo in un nuovo , bloccando X di nuovo

Dal momento che w Non è mai uscito il primo richiamo di A, X è ancora bloccato. Questo è chiamato ri-ingresso - mentre la funzione A non è ancora tornata, la funzione A è chiamata di nuovo. Se A si basa su uno stato statico globale, questo può causare un "bug di rientro", in cui prima che lo stato statico venga ripulito dall'uscita della funzione, la funzione viene eseguita di nuovo e i valori calcolati a metà si scontrano con l'inizio di la seconda chiamata.

In questo caso, ci imbattiamo in una serratura che stiamo già tenendo. Se il blocco è rientrato consapevole, si renderà conto che siamo lo stesso thread che tiene già il blocco e lasciaci passare. Altrimenti, si bloccherà per sempre - sarà in attesa di un blocco che già tiene.

In java, lock e synchronized sono rientrati consapevoli: se un blocco è trattenuto da un thread e il thread tenta di riacquistare lo stesso blocco, è consentito. Quindi, se scrivessimo lo pseudocodice sopra in Java, non si bloccerebbe.

7

Java concorrenza in pratica afferma il libro - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

Lasciatemi spiegare che cosa significa esattamente. Prima di tutto le serrature intrinseche sono rientranti per natura. Il modo in cui viene raggiunta la rientranza consiste nel mantenere un contatore per il numero di blocchi acquisiti e il proprietario della serratura. Se il conteggio è 0 e nessun proprietario è associato ad esso, significa che il blocco non è trattenuto da nessun thread. Quando un thread acquisisce il blocco, JVM registra il proprietario e imposta il contatore su 1.Se lo stesso thread tenta di acquisire il blocco, il contatore viene incrementato e quando il thread proprietario esiste il contatore di blocchi sincronizzati viene decrementato. Quando il conteggio raggiunge 0, il blocco viene rilasciato.

Un semplice esempio potrebbe essere -

public class Test { 
    public synchronized void performTest() { 
     //... 
    } 
} 

public class CustomTest extends Test { 
    public synchronized void performTest() { 
     //... 
     super.performTest(); 
    } 
} 

senza rientranza ci sarebbe una situazione di stallo.

enter image description here