Belenorovo

Java: Thread-safe Serializable Singleton

Jak udělat thread-safe serializable singleton v Javě.
Obvyklý způsob, využívající synchronize a různé kontroly, typicky Double Checked Locking, neřeší problém s thread-safety, protože prostě není nijak zaručeno pořadí provádění instrukcí. Jediné místo, kdy JVM zaručuje vláknovou bezpečnost (ehm :-) je při statické inicializaci načítaných tříd, takže:

Eager loading (při prvním použití třídy Singleton se inicializuje INSTANCE):

public class Singleton {
public final static Singleton INSTANCE = new Singleton();

}

Lazy loading (INSTANCE se inicializuje až při volání metody getInstance(), která používá vnitřní třídu):

public class Singleton {
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}

private Singleton() {}
}

V nadpisu je i zmínka o serializaci. Problém je v tom, že při deserializaci singletonu se fakticky nepoužije správná instance singletonu, ale udělá se nová. Toto jde řešit pomocí readResolve() a lze velmi dobře použít u enumerací dělaných pomocí singletonu.

public class Singleton implements Serializable {
public final static Singleton INSTANCE = new Singleton();

private Object readResolve() throws java.io.ObjectStreamException {
return INSTANCE;
}
}

Přičemž readResolve() je normální metoda, která může sahat na položky své instance, které jsou před zavoláním readResolve() inicializovány, takže pokud třeba je v enumeraci použito id jako identifikátor instance a getInstance(int) slouží jako metoda k získání instance, pak lze:

public class Singleton implements Serializable {
private int id;

public Singleton getInstance(int id){
...
}

private Object readResolve() throws java.io.ObjectStreamException {
return getInstance(this.id);
}
}

Past na turisty: Pokud loadujete pomocí více classloaderů (např. J2EE aplikace), tak se může stát, že budete mít více instancí "singletonu", čili na singletony obecně pozor :-)

Pozor, aktualizace: Ukazuje se, že od verze 1.5 lze použít "volatile" při deklaraci proměnné, která bude držet instanci singletonu, k tomu, aby double-checked locking fungoval, takže proč ne :-)
Kategorie: Programování.

Komentáře

Nenašel jsem žádné komentáře

Přidání komentáře

Jméno *
E-mail Odkaz
Zpráva *