Czy jest to lepsza wersja Double Check Locking bez niestabilności i narzutu synchronizacji
Poniżej fragment kodu z efektywnej Java 2nd Edition Double Checked Locking
// Podwójne sprawdzenie idiomu dla leniwej inicjalizacji pól instancji
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;
}
Z tego, co wiem, głównym problemem związanym z podwójnym sprawdzaniem blokowania jest zmiana kolejności wewnątrz drugiego blokowania kontroli, tak aby drugi wątek mógł zobaczyć wartości pola / wyniku jako zestawu, który może być faktycznie wykonywany. Aby tego uniknąć, odwołujemy się do pola jako zmiennego w celu zapewnienia widoczności i zmiany kolejności.
Ale można to osiągnąć również za pomocą poniższego kodu
private FieldType field; // non volatile
private volatile boolean fence = false;
FieldType getField() {
if (field == null) { // First check (no locking) // no volatile read
synchronized(this) { // inside synch block no problem of visibilty will latest //value of field
if (field == null) {// Second check (with locking)
Object obj = computeFieldValue();
fence = true; // any volatile write will take. this will make sure statements are //not reorder with setting field as non null.
field = (FieldType)obj; // this will be only set after computeFieldValue has been //completed fully
}
}
}
return field;
}
Tak więc po zakończeniu inicjalizacji żaden wątek nie będzie musiał odnosić się do odczytu zmiennego lub narzutu synchronizacji. Sprawdź, czy moje założenia są słuszne, czy nie?