Le pattern Singleton avec la combinaison de chargement paresseux et le fil de sécurité
J'ai été faire quelques recherches sur les singletons, spécialement en ce qui concerne paresseux vs désireux d'initialisation de singletons.
Un exemple de désireux de l'initialisation:
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 qu'il est désireux d'initialisation et le fil de sécurité est laissée à la jvm
mais maintenant, je veux avoir ce même modèle, mais avec l'initialisation tardive.
donc je venir 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 de
private static final Foo INSTANCE = new Foo();
n'est exécuté que lorsque la classe FooLoader est effectivement utilisé, cela prend en charge les paresseux de l'instanciation, et il est garanti d'être thread-safe.
Est-ce correct?
- En double stackoverflow.com/q/5842273/823393
- Ce n'est pas vraiment l'initialisation tardive si? L'instance peut être chargé avant le
getInstance
méthode invoquée. - Ce n'est certainement paresseux. Le
INSTANCE
est instancié sur la référence première de la classe. Qui ne sera référencé dans la première invocation degetInstance
. Mais je voudrais enlever la création de vérifier dans le constructeur. - dites-moi, qu'arriverait-il si je l'ai fait -
Class.forName("Foo")
? - il va créer la instace de la classe Foo. Que initialixation comprend les champs statiques et thr statique bloc. Il ne comprend pas statique classes enfant. vous pouvez essayer vous-même pour voir.
- C'est le Titulaire du modèle.
Vous devez vous connecter pour publier un commentaire.
Votre deuxième extrait de code est, à mon avis, la meilleure façon de thread-safe paresseusement de l'initialisation d'un singleton. En fait, elle a un nom de modèle
Initialisation sur demande du titulaire de l'idiome
Je vous suggère de l'utiliser.
Foo.class
et pas l'instance.De la première conception est en fait paresseux. Pensez à ce sujet, l'instance n'est créé que lorsque la classe est initialisée; la classe n'est initialisé lors de l'
getSingleton()
méthode est appelée [1]. Si l'instance n'est créé que lorsque c'est demandé, c'est à dire qu'il est paresseusement créé.[1] http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1
getInstance()
)Le second est très mauvais en termes de lisibilité, le premier est adapté. Jetez un oeil à cette l'article. Son environ le double de vérifier le verrouillage, mais également vous donner des informations à l'échelle sur les singletons de multithreading.
getInstance
et seulement d'invoquer l'autre méthode qui fait un simple printlnLa meilleure façon est en fait d'utiliser le Enum Façon:
À mon avis, ce n'est pas approprié au modèle à utiliser. Il fait des hypothèses sur la JVM du comportement qui ne sont pas anodines et déroutant. Aussi, il a un mannequin de classe. Mannequin classes doivent être évités si possible.
Je suggère l'approche directe:
... bien que cela ne fonctionne pas comme-est - ce n'est pas thread-safe.. Ce que vous voulez vraiment est le double-vérifier le modèle présenté dans l'Article 71 de Bloch Efficace Java; voir ici. L'adaptation de l'exemple sur le lien à votre cas, nous obtenons:
Notes: