Двічі перевірено блокування. За великим рахунком.
Парадигма, за якою я почав вивчати проблеми, коли працював у BEA, полягає в тому, що люди перевірятимуть одиночку таким чином:
public Class MySingleton {
private static MySingleton s_instance;
public static MySingleton getInstance() {
if(s_instance == null) {
synchronized(MySingleton.class) { s_instance = new MySingleton(); }
}
return s_instance;
}
}
Це ніколи не працює, тому що інший потік, можливо, потрапив до синхронізованого блоку, і s_instance вже не є нульовою. Тож природна зміна полягає в тому, щоб це зробити:
public static MySingleton getInstance() {
if(s_instance == null) {
synchronized(MySingleton.class) {
if(s_instance == null) s_instance = new MySingleton();
}
}
return s_instance;
}
Це не працює, тому що модель пам'яті Java не підтримує її. Вам потрібно оголосити s_instance як мінливу, щоб вона працювала, і навіть тоді вона працює лише на Java 5.
Люди, які не знайомі з тонкощами моделі пам'яті Java, псують це весь час .