2012-11-21 12 views
5

In JCIP, sezione 3.2.1 "Pratiche di costruzione sicura", è presente un avviso per la perdita di this in un altro thread dal costruttore, "anche se la pubblicazione è l'ultima istruzione nel costruttore". Quest'ultima parte mi sembra troppo forte, ed è fornita senza giustificazione. Cosa succede dopo la costruzione che devo essere così attento a evitare? Ci sono delle eccezioni? Sono interessato perché recentemente ho presentato del codice in cui ho fatto proprio questo, e voglio decidere se c'è una giustificazione per tornare indietro e refactoring.java: perché non dovrebbe essere permesso di sfuggire al costruttore?

+1

http://msmvps.com/blogs/jon_skeet/archive/2010/09/02/don-t-let-this-get-away.aspx – SLaks

risposta

4

Per quanto riguarda il modello di memoria Java, l'uscita del costruttore svolge un ruolo nella semantica del campo finale, quindi c'è una differenza se un'istruzione è prima o dopo l'uscita del costruttore.

This works       This doesn't work 
------------------------------------------------------------- 

static Foo shared;     static Foo shared; 

class Foo       class Foo 
{         { 
    final int i;      final int i; 
    Foo()        Foo() 
    {         { 
     i = 1;        i = 1; 
              shared = this; 
    }         } 
}         } 

shared = new Foo();    new Foo(); 

(Nota: shared non è volatile, la pubblicazione è attraverso gara di dati.)

L'unica differenza tra i 2 esempi sta assegnando shared prima o dopo l'uscita del costruttore. Nel secondo esempio, i=1 può essere riordinato dopo l'assegnazione.

Tuttavia, se la pubblicazione è un'azione sincronizzata, ad es. attraverso una variabile volatile, quindi va bene; altri thread osserveranno un oggetto completamente inizializzato; i campi non hanno nemmeno bisogno di final.

La pubblicazione tramite dati race (o qualsiasi altra cosa tramite la data race) è un'attività molto complessa che richiede un ragionamento molto accurato. Se si evita la corsa ai dati, le cose sono molto più semplici. Se il codice non contiene dati, non c'è differenza tra la perdita di this immediatamente prima dell'uscita del costruttore e la pubblicazione immediata dopo l'uscita del costruttore.

4

Non si dovrebbe mai perdere this da un costruttore in qualsiasi punto, "anche [...] nell'ultima istruzione." Dal momento che lo this non è completamente costruito, possono accadere cose molto strane. Vedi this SO answer su una domanda molto simile.

4

Non si dovrebbe mai passare this fuori del costruttore (noto come "perdite this")

Una ragione per cui non si dovrebbe fare, anche se è l'ultima riga del costruttore, è che la JVM è consentito per riordinare le istruzioni finché l'effetto sul thread corrente non è influenzato. Se this viene passato a un processo in esecuzione in un altro thread, il riordino può causare bug strani e sottili.

Un'altra ragione è che le sottoclassi possono fornire la propria inizializzazione, quindi la costruzione potrebbe non essere completa nell'ultima riga del costruttore della classe.

Problemi correlati