Frage

Betrachten Sie die „Double-Check-Idiom für die verzögerte Initialisierung von Instanzfeldern“:

// Item 71 in Effective Java copied from dieses Interview mit 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;
}

Ich möchte das Feld auf sichere Weise zurücksetzen können (in meinem Fall das erneute Laden aus der Datenbank erzwingen).Ich gehe davon aus, dass wir dies mit einer Reset-Methode erreichen könnten:

void reset() {
   field = null;
}

Ist dies die Standardmethode zum Zurücksetzen des Feldes?Ist es sicher?Irgendwelche Fallstricke?Ich frage, weil Bloch die folgende Warnung zum doppelt überprüften Lazy-Loading ausgesprochen hat:„Die Redewendung ist sehr schnell, aber auch kompliziert und heikel, also lassen Sie sich nicht dazu verleiten, sie in irgendeiner Weise zu ändern.Einfach kopieren und einfügen – normalerweise keine gute Idee, aber hier angebracht.“

Vielen Dank im Voraus, Playa aus dem Himalaya.

War es hilfreich?

Lösung

Ja, das ist Thread-sicher.

Die synchronisierten Block ist mehrere Threads nicht unnötig zu verhindern computeFieldValue() aufrufen. Da field flüchtig ist, sind die Zugriffe in reset und getField alle gut geordnet.

Wenn die erste Prüfung nicht-null ist, getField erfolgt; result zurückgegeben.

Andernfalls wird eine Sperre erlangt, andere Gewinde mit Ausnahme, dass das Feld nicht-null gesetzt könnte, aber ermöglicht jeden Thread field bis auf null gesetzt. Wenn ein Thread field nicht auf null gesetzt, sollte nichts geändert haben; das ist der Zustand, der den Faden in den synchronisierten Block erhielt. Wenn ein anderer Thread bereits die Sperre nach dem aktuellen Thread Check erworben hatte, und setzen Sie das Feld auf einen Wert ungleich Null, die zweite Prüfung wird das erkennen.

Andere Tipps

Ich denke, das sicher sein sollte, aber nur, weil Sie das Feld in einer lokalen Variablen sind zu speichern. Nachdem dies geschehen ist, gibt es keine Möglichkeit für die lokale Variable Bezug auf magische Weise auf null zu ändern, auch wenn ein anderer Thread auf halbem Weg Feldwert durch zurücksetzt.

Es scheint, wie dies so lange arbeiten wie die Reset-Methode die reset() Methode oben aufgeführt ist. Wenn jedoch die reset() Methode ein neues Objekt (wie unten) instanziiert, konnte nicht Sie am Ende möglicherweise etwas Rückkehr anders als beabsichtigt?

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

Ich denke, es hängt davon ab, genau das, was Sie von Thread-sicher bedeuten.

Sie könnten mit einer Situation landen, wo eine erste Instanz nach einer Sekunde verwendet. Das mag in Ordnung sein, oder auch nicht.

Ich denke, die Methode reset() ist nicht korrekt.Wenn Sie Punkt 71 lesen, werden Sie Folgendes finden:

Dieser Code erscheint möglicherweise etwas kompliziert.Insbesondere kann die Notwendigkeit des lokalen variablen Ergebnisses unklar sein.Diese Variable stellt sicher, dass das Feld vorhanden istschreibgeschützt einmal im allgemeinen Fall, wenn es bereits initialisiert ist.

Eine verzögerte Initialisierung setzt das nicht voraus Feld könnte sich geändert haben.Wenn das Feld zwischen diesen Operatoren auf Null gesetzt wird:

FieldType result = field;
if (result == null) { // First check (no locking)

getField() liefert falsches Ergebnis.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top