Domanda

Considera il linguaggio "ricontrolla doppio" per l'inizializzazione lenta dei campi di istanza " ;:

// Item 71 in Effective Java copied from this interview with Bloch.
private volatile FieldType field;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
     return result;
}

Voglio essere in grado di ripristinare il campo in modo sicuro (forzare il mio caricamento dal database, nel mio caso). Presumo che potremmo farlo con un metodo di ripristino:

void reset() {
   field = null;
}

È questo il modo standard di reimpostare il campo? È sicuro? Alcune insidie? Lo sto chiedendo perché Bloch ha dato il seguente avvertimento sul caricamento lento ricontrollato: " L'idioma è molto veloce ma anche complicato e delicato, quindi non essere tentato di modificarlo in alcun modo. Copia e incolla, di solito non è una buona idea, ma è appropriato qui. & Quot;

Grazie in anticipo, Playa dall'Himalaya.

È stato utile?

Soluzione

Sì, questo è thread-safe.

Il blocco sincronizzato serve per impedire a più thread di chiamare inutilmente computeFieldValue () . Poiché field è volatile, gli accessi in reset e getField sono tutti ben ordinati.

Se il primo controllo è non nullo, getField viene eseguito; risultato viene restituito.

Altrimenti, viene acquisito un blocco, escludendo qualsiasi altro thread che potrebbe impostare il campo su un valore non nullo, ma consentendo a qualsiasi thread di impostare campo su null. Se un thread imposta field su null, nulla dovrebbe essere cambiato; questa è la condizione che ha portato il thread nel blocco sincronizzato. Se un altro thread ha già acquisito il blocco dopo il controllo del thread corrente e ha impostato il campo su un valore non nullo, il secondo controllo lo rileverà.

Altri suggerimenti

Penso che questo dovrebbe essere sicuro, ma solo perché stai memorizzando il campo in una variabile locale. Al termine, non è possibile che il riferimento alla variabile locale passi magicamente a null, anche se un altro thread sta ripristinando il valore del campo a metà.

Sembra che funzionerà fintanto che il metodo di ripristino è il metodo reset () sopra elencato. Tuttavia, se il metodo reset () crea un'istanza di un nuovo oggetto (come sotto), non potresti finire per restituire potenzialmente qualcosa di diverso da quello che volevi?

void reset() {
    field = new FieldType();
}

Suppongo che dipenda esattamente da cosa intendi per thread-safe.

Potresti finire con una situazione in cui una prima istanza viene utilizzata dopo un secondo. Potrebbe andare bene, oppure no.

Penso che il metodo reset () non sia corretto. Se leggi l'articolo 71, troverai:

Questo codice può apparire un po 'contorto. In particolare, la necessità del locale il risultato variabile potrebbe non essere chiaro. Ciò che questa variabile fa è assicurarsi che quel campo sia sola lettura una volta nel caso comune in cui è già inizializzato.

L'inizializzazione lenta non suppone che campo potrebbe essere cambiato. Se il campo verrà impostato su null tra questi operatori:

FieldType result = field;
if (risultato == null) {// Primo controllo (nessun blocco)

getField () fornisce risultati errati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top