Oui il faut. Il existe plusieurs méthodes que vous pouvez utiliser pour assurer la sécurité des threads avec une initialisation différée:
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 thread soit synchronisé alors qu'en réalité seuls les premiers doivent l'être.
Vérifiez 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) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Cette solution garantit que seuls les premiers threads qui tentent d'acquérir votre singleton doivent passer par le processus d'acquisition du verrou.
Initialisation à la demande :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Cette solution tire parti des garanties du modèle de mémoire Java sur l'initialisation de classe pour assurer la sécurité des threads. Chaque classe ne peut être chargée qu'une seule fois et ne sera chargée que lorsque cela sera nécessaire. Cela signifie que la première fois getInstance
est appelée, InstanceHolder
sera chargée et instance
créée, et comme elle est contrôlée par ClassLoader
s, aucune synchronisation supplémentaire n'est nécessaire.
Draconian synchronization
etDouble check synchronization
getInstance () - la méthode doit être statique!static
, mais cela aurait plus de sens s'ils l'étaient. Modifié comme demandé.r
n'est pas nécessaire pour l'exactitude. C'est juste une optimisation pour éviter d'accéder au champ volatil, car c'est beaucoup plus cher que d'accéder à une variable locale.Ce modèle effectue une initialisation paresseuse thread-safe de l'instance sans synchronisation explicite!
Cela fonctionne car il utilise le chargeur de classe pour faire toute la synchronisation pour vous gratuitement: la classe
MySingleton.Loader
est d'abord accédée à l'intérieur de lagetInstance()
méthode, donc laLoader
classe se charge lorsqu'ellegetInstance()
est appelée pour la première fois. De plus, le chargeur de classe garantit que toute l'initialisation statique est terminée avant que vous n'ayez accès à la classe - c'est ce qui vous assure la sécurité des threads.C'est comme de la magie.
C'est en fait très similaire au modèle enum de Jhurtado, mais je trouve que le modèle enum est un abus du concept enum (bien que cela fonctionne)
la source
final
devrait être ajouté. Terminé.Si vous travaillez sur un environnement multithread en Java et avez besoin de garantir que tous ces threads accèdent à une seule instance d'une classe, vous pouvez utiliser un Enum. Cela aura l'avantage supplémentaire de vous aider à gérer la sérialisation.
puis demandez simplement à vos threads d'utiliser votre instance comme:
la source
Oui, vous devez effectuer une
getInstance()
synchronisation. Si ce n'est pas le cas, il peut se produire une situation dans laquelle plusieurs instances de la classe peuvent être créées.Considérez le cas où vous avez deux threads qui appellent
getInstance()
en même temps. Imaginez maintenant que T1 s'exécute juste après lainstance == null
vérification, puis T2 s'exécute. À ce stade, l'instance n'est ni créée ni définie, donc T2 passera la vérification et créera l'instance. Imaginez maintenant que l'exécution revienne à T1. Maintenant, le singleton est créé, mais T1 a déjà fait la vérification! Il procédera à nouveau à la création de l'objet! FairegetInstance()
synchronisé empêche ce problème.Il existe plusieurs façons de rendre les singletons thread-safe, mais la
getInstance()
synchronisation est probablement la plus simple.la source
Enum singleton
Le moyen le plus simple d'implémenter un Singleton qui est thread-safe consiste à utiliser un Enum
Ce code fonctionne depuis l'introduction d'Enum dans Java 1.5
Verrouillage vérifié deux fois
Si vous voulez coder un singleton «classique» qui fonctionne dans un environnement multithread (à partir de Java 1.5), vous devez utiliser celui-ci.
Ce n'est pas thread-safe avant 1.5 car l'implémentation du mot-clé volatile était différente.
Chargement anticipé de Singleton (fonctionne même avant Java 1.5)
Cette implémentation instancie le singleton lorsque la classe est chargée et assure la sécurité des threads.
la source
Vous pouvez également utiliser un bloc de code statique pour instancier l'instance au chargement de la classe et éviter les problèmes de synchronisation des threads.
la source
instance
finale 2. Vous devez rendregetInstance()
statique.Reportez-vous à cet article pour connaître la meilleure façon d'implémenter Singleton.
Quel est un moyen efficace d'implémenter un modèle de singleton en Java?
Cela dépend de la façon dont vous avez implémenté la méthode.Si vous utilisez le double verrouillage sans variable volatile, vous pouvez obtenir un objet Singleton partiellement construit.
Reportez-vous à cette question pour plus de détails:
Pourquoi volatile est-il utilisé dans cet exemple de verrouillage à double vérification
Non requis si vous implémentez le Singleton de la manière ci-dessous
Reportez-vous à cette question pour plus de détails
Modèle de conception Java Singleton: questions
la source
Source: Java efficace -> Point 2
Il suggère de l'utiliser, si vous êtes sûr que cette classe restera toujours singleton.
la source