Question

Pourquoi le modèle comme cassée? Ça à l'air bien pour moi? Toutes les idées?

public static Singleton getInst() {
    if (instace == null) createInst();
    return instace;
}

private static synchronized createInst() {
     if (instace == null) {
         instace = new Singleton(); 
     }
}
Était-ce utile?

La solution

Il semble bien à première vue, mais cette technique a beaucoup de problèmes et doit généralement être évité subtiles. Par exemple, considérez la séquence des événements suivants:

  1. Discussion A avis que la valeur est non initialisé, il obtient le verrouiller et commence à initialiser le valeur.
  2. Le code généré par le compilateur est autorisé de mettre à jour la variable partagée le point à une partie construite Un objet avant a fini exécution de l'initialisation.
  3. Avis Discussion B que le partage variable a été initialisé (ou si il semble), et retourne sa valeur. Parce que le thread B croit que la valeur est déjà initialisé, il ne acquérir le verrou. Si B utilise le objet avant que toutes les l'initialisation effectuée par A est vu par B le programme va probablement planter.

Vous pourriez éviter cela en utilisant le mot-clé « volatile » pour gérer correctement vos instances singleton

Autres conseils

Toute la discussion est un énorme gaspillage de temps sans fin du cerveau. 99,9% du temps, singletons ne pas de frais d'installation importants et il n'y a aucune raison que ce soit pour les configurations parvins à atteindre non synchronisé chargement garanti-paresseux.

Voici comment vous écrivez un Singleton en Java:

public class Singleton{
    private Singleton instance = new Singleton();
    private Singleton(){ ... }
    public Singleton getInstance(){ return instance; }
}

Mieux encore, en font un ENUM:

public enum Singleton{
    INSTANCE;
    private Singleton(){ ... }
}

Je ne sais pas si elle est cassée, mais il est pas vraiment la solution la plus efficace en raison de synchronisation qui est assez cher. serait à l'aide du « Initialisation à la demande Titulaire Idiom », qui charge votre singleton en mémoire la première fois qu'il est demandé, comme son nom l'indique, ainsi le chargement paresseux Une meilleure approche. Le plus grand avantage que vous obtenez avec cet idiome est que vous n'avez pas besoin de synchroniser parce que les JLS assure que le chargement de la classe est de série.

entrée wikipedia détaillée sur le sujet: http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

Une autre chose à garder à l'esprit est que, puisque les cadres d'injection de dépendance tels que Spring et Guice ont vu le jour, les instances de classe sont en cours de création créés et gérés par ces conteneurs et ils vous fournir un Singleton si on le désire, il ne vaut pas casser votre tête au-dessus, sauf si vous voulez apprendre à idée derrière le modèle, ce qui est utile. Notez également que les singletons fournis par ces conteneurs du CIO sont singletons par exemple de conteneurs, mais en général, vous aurez un conteneur du CIO par application, de sorte qu'il ne devienne pas un problème.

Le problème est le suivant: Votre machine virtuelle peut réordonner votre code et les champs ne sont pas toujours les mêmes pour différents threads. Jetez un coup d'œil à ceci: http://www.ibm.com/ developerworks / java / bibliothèque / j-dcl.html . L'utilisation du mot-clé volatile doit corriger cela, mais son cassé avant java 1.5.

La plupart du simple verrouillage vérifié de temps est plus que rapide, essayez ceci:

// single checked locking: working implementation, but slower because it syncs all the time
public static synchronized Singleton getInst() {
    if (instance == null) 
        instance = new Singleton();
    return instance;
}

ont également un oeil à Java efficace, où vous trouverez un grand chapitre sur ce sujet.

Pour résumer cela:. Dont ne revérifié verrouillage, il y a de meilleures idoms

initialisation à la demande Titulaire Idiom , yup qu'il est:

public final class SingletonBean{

    public static SingletonBean getInstance(){
        return InstanceHolder.INSTANCE;
    }

    private SingletonBean(){}

    private static final class InstanceHolder{
        public static final SingletonBean INSTANCE = new SingletonBean();
    }

}

Bien que Joshua Bloch recommande également le modèle du Enum Effective Java Chapitre 2, point 3:

// Enum singleton - the prefered approach
public enum Elvis{
    INSTANCE;
    public void leaveTheBuilding(){ ... }
}

Cela ne répond pas à votre question (d'autres l'ont déjà fait), mais je veux vous raconter mon expérience avec singletons / paresseux objets initialisés:

Nous avons eu quelques singletons dans notre code. Une fois que nous avons dû ajouter un paramètre de constructeur à un singleton et avait un sérieux problème, car le constructeur de ce singleton a été invoqué sur le getter. Il n'y avait que les solutions suivantes sont possibles:

  • fournir un getter statique (ou un autre singleton) pour l'objet qui a été nécessaire pour initialiser ce singleton,
  • passer l'objet pour initialiser le singleton en tant que paramètre pour le getter ou
  • se débarrasser du singleton par des instances passant autour.

Enfin, la dernière option était la voie à suivre. Maintenant, nous initialisons tous les objets au démarrage de l'application et passage requise autour des cas (peut-être comme une petite interface). Nous n'avons pas regretté cette décision, parce que

  • les dépendances d'un morceau de code est limpide,
  • nous pouvons tester notre code beaucoup plus facile en fournissant des implémentations factices des objets requis.

La plupart des réponses sont correctes ici pourquoi il est cassé, mais sont incorrects ou suggérer des stratégies douteuses d'une solution.

Si vous avez vraiment, vraiment devez utiliser un singleton (qui, dans la plupart des cas, vous ne devrait pas , car il détruit testabilité, moissonneuses-batteuses logique sur la façon de construire une classe avec la le comportement de la classe, jonche les classes qui utilisent le singleton avec la connaissance de la façon d'obtenir un, et conduit à un code plus fragile) et sont préoccupés par la synchronisation, la bonne solution est d'utiliser statique initialiseur pour instancier l'instance.

private static Singleton instance = createInst();

public static Singleton getInst() {
    return instance ;
}

private static synchronized createInst() {
    return new Singleton(); 
}

Les garanties de spécification du langage Java qui initiailzers statiques seront exécutées une seule fois, quand une classe est chargée pour la première fois, et de manière thread-safe garantie.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top