Je faisais des recherches sur les singletons, en particulier sur l'initialisation paresseuse ou désirée des singletons.
Un exemple d'initialisation désirée:
public class Singleton
{
//initialzed during class loading
private static final Singleton INSTANCE = new Singleton();
//to prevent creating another instance of Singleton
private Singleton(){}
public static Singleton getSingleton(){
return INSTANCE;
}
}
mais comme indiqué ci-dessus, il s’agit d’une initialisation rapide et la sécurité des threads est laissée à jvm
alors je viens avec cette approche:
public final class Foo {
private static class FooLoader {
private static final Foo INSTANCE = new Foo();
}
private Foo() {
if (FooLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
}
public static Foo getInstance() {
return FooLoader.INSTANCE;
}
}
Comme indiqué ci-dessus depuis la ligne
private static final Foo INSTANCE = new Foo();
n’est exécuté que lorsque la classe FooLoader est réellement utilisée, elle s’occupe de l’instanciation paresseuse et garantit la sécurité des threads.
Est-ce correct?
Votre deuxième extrait de code est, à mon avis, le meilleur moyen d’initialiser un singleton en toute sécurité. Il a en fait un nom de modèle
Idiome de titulaire d'initialisation à la demande
Je vous suggère de l'utiliser.
Votre première conception est en réalité paresseuse. Pensez-y, l'instance n'est créée que lorsque la classe est initialisée; la classe n'est initialisée que lorsque la méthode getSingleton()
est appelée [1]. Ainsi, l’instance n’est créée que sur demande, c’est-à-dire créée paresseusement.
[1] http://docs.Oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1
Le second est très mauvais en termes de lisibilité, le premier convient. Regardez cet article article . Il s’agit d’un verrouillage à double contrôle, mais vous donnera également de nombreuses informations sur le multithreading de singletons.
Le meilleur moyen est d’utiliser le Enum Way :
public enum Singleton {
INSTANCE;
public void execute (String arg) {
//... perform operation here ...
}
}
À mon avis, ceci est un modèle inapproprié à utiliser. Il émet des hypothèses sur le comportement de la machine virtuelle qui sont non triviales et déroutantes. En outre, il a une classe factice. Les cours factices doivent être évités autant que possible.
Je suggère l'approche simple:
public class Foo {
private volatile static final Foo instance = null;
private Foo() {
}
public static Foo instance() {
if (instance == null) instance = new Foo();
return instance;
}
}
}
... bien que cela ne fonctionne pas tel quel - ce n'est pas sécurisé du point de vue des threads. Ce que vous voulez vraiment, c'est le motif de double vérification présenté à la rubrique 71 de Bloch's Effective Java; voir ici . En adaptant l'exemple du lien vers votre cas, nous obtenons:
public class Foo {
private volatile static final Foo instance = null;
private Foo() {
}
public static Foo instance() {
if (instance != null) return instance;
synchronized(instance) {
Foo result = instance;
if (instance == null) {
result = instance = new Foo();
return result;
}
}
}
Remarques: