Oui, c'est nécessaire. Il existe plusieurs méthodes que vous pouvez utiliser pour garantir la sécurité des threads avec une initialisation paresseuse:
Synchronisation draconienne:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Cette solution nécessite que chaque fil soit synchronisé alors qu'en réalité seuls les premiers ont besoin de l'être.
Double vérification de la synchronisation:
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // Pendant que nous attendions le verrou, un autre
r = instance; // fil pourrait avoir instancié l'objet.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Cette solution garantit que seuls les premiers fils qui essaient d'acquérir votre singleton doivent passer par le processus d'acquisition du verrou.
Initialisation sur demande:
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Cette solution exploite les garanties du modèle de mémoire Java concernant l'initialisation de classe pour garantir la sécurité des threads. Chaque classe ne peut être chargée qu'une seule fois, et elle ne le sera que lorsqu'elle est nécessaire. Cela signifie que la première fois que getInstance
est appelé, InstanceHolder
sera chargé et instance
sera créé, et comme cela est contrôlé par des ClassLoader
s, aucune synchronisation supplémentaire n'est nécessaire.