code - java singleton with parameters



Java Singleton et synchronisation (6)

Quelle est la meilleure façon d'implémenter Singleton en Java, dans un environnement multithread?

Reportez-vous à ce post pour connaître la meilleure façon d'implémenter Singleton.

Qu'est-ce qu'un moyen efficace d'implémenter un pattern singleton en Java?

Que se passe-t-il lorsque plusieurs threads tentent d'accéder à la méthode getInstance () en même temps?

Cela dépend de la façon dont vous avez implémenté la méthode. Si vous utilisez un double verrouillage sans variable volatile, vous pouvez obtenir un objet Singleton partiellement construit.

Reportez-vous à cette question pour plus de détails:

Pourquoi la volatilité est-elle utilisée dans cet exemple de verrouillage à double vérification?

Pouvons-nous synchroniser getInstance () de singleton?

La synchronisation est-elle réellement nécessaire lorsque vous utilisez des classes Singleton?

Non requis si vous implémentez le Singleton de la manière suivante

  1. intitalisation statique
  2. enum
  3. LazyInitalaization avec Initialization-on-demand_holder_idiom

Reportez-vous à cette question pour plus de détails

Java Singleton Design Pattern: Questions

https://ffff65535.com

S'il vous plaît clarifier mes questions concernant Singleton et Multithreading:

  • Quelle est la meilleure façon d'implémenter Singleton en Java, dans un environnement multithread?
  • Que se passe-t-il lorsque plusieurs threads tentent d'accéder à la méthode getInstance() en même temps?
  • Pouvons-nous synchronized getInstance() de singleton?
  • La synchronisation est-elle réellement nécessaire lorsque vous utilisez des classes Singleton?

Ce modèle effectue une initialisation paresseuse sans threading de l'instance sans synchronisation explicite!

public class MySingleton {

     private static class Loader {
         static final MySingleton INSTANCE = new MySingleton();
     }

     private MySingleton () {}

     public static MySingleton getInstance() {
         return Loader.INSTANCE;
     }
}

Cela fonctionne parce qu'il utilise le chargeur de classe pour faire toute la synchronisation pour vous gratuitement: La classe MySingleton.Loader est d'abord accédée dans la méthode getInstance() , donc la classe Loader charge quand getInstance() est appelée pour la première fois. De plus, le chargeur de classe garantit que toute l'initialisation statique est terminée avant d'avoir accès à la classe - c'est ce qui vous donne la sécurité du thread.

C'est comme de la magie.

C'est en fait très similaire au motif enum de Jhurtado, mais je trouve que le motif enum est un abus du concept enum (bien que cela fonctionne)


Oui il faut. Il existe plusieurs méthodes que vous pouvez utiliser pour obtenir une sécurité de thread 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 thread soit synchronisé alors qu'en réalité seuls les premiers doivent 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) {    // 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 elle ne sera chargée que lorsque cela sera nécessaire. Cela signifie que la première fois que getInstance est appelée, InstanceHolder sera chargé et que l' instance sera créée, et que celle-ci est contrôlée par ClassLoader s, aucune synchronisation supplémentaire n'est nécessaire.


Oui, vous devez synchroniser getInstance() . Si ce n'est pas le cas, il peut se produire une situation où plusieurs instances de la classe peuvent être créées.

Prenons le cas où vous avez deux threads qui appellent getInstance() en même temps. Maintenant, imaginez que T1 s'exécute juste après l' instance == null check, puis T2 s'exécute. À ce stade, l'instance n'est pas créée ou définie, donc T2 passera la vérification et créera l'instance. Maintenant, imaginez que l'exécution repasse en T1. Maintenant le singleton est créé, mais T1 a déjà fait le contrôle! Il procédera à refaire l'objet! Rendre getInstance() synchronisé empêche ce problème.

Il y a quelques façons de rendre les singletons thread-safe, mais synchroniser getInstance() est probablement le plus simple.


Vous pouvez également utiliser le bloc de code statique pour instancier l'instance lors du chargement de la classe et éviter les problèmes de synchronisation des threads.

public class MySingleton {

  private static final MySingleton instance;

  static {
     instance = new MySingleton();
  }

  private MySingleton() {
  }

  public static MySingleton getInstance() {
    return instance;
  }

}

public class Elvis { 
   public static final Elvis INSTANCE = new Elvis();
   private Elvis () {...}
 }

Source: Java efficace -> Article 2

Il suggère de l'utiliser, si vous êtes sûr que la classe restera toujours singleton.





singleton