Singleton est l’un des motifs de conception créationnelle les plus largement utilisés pour restreindre l’objet créé par les applications. Si vous l’utilisez dans un environnement multithreadé, alors la sécurité des threads de la classe singleton est très importante. Dans les applications du monde réel, des ressources comme les connexions de base de données ou les systèmes d’information d’entreprise (EIS) sont limitées et doivent être utilisées judicieusement pour éviter toute pénurie de ressources. Pour y parvenir, nous pouvons mettre en œuvre un modèle de conception Singleton. Nous pouvons créer une classe enveloppe pour la ressource et limiter le nombre d’objets créés à un seul à l’exécution.
Singleton Thread Safe en Java
En général, nous suivons les étapes ci-dessous pour créer une classe singleton :
- Créer le constructeur privé pour éviter toute nouvelle création d’objet avec l’opérateur new.
- Déclarer une instance statique privée de la même classe.
- Fournir une méthode publique et statique qui renverra la variable d’instance de la classe singleton. Si la variable n’est pas initialisée, alors l’initialiser, sinon simplement renvoyer la variable d’instance.
En utilisant les étapes ci-dessus, j’ai créé une classe singleton qui ressemble à ceci. ASingleton.java
package com.journaldev.designpatterns;
public class ASingleton {
private static ASingleton instance = null;
private ASingleton() {
}
public static ASingleton getInstance() {
if (instance == null) {
instance = new ASingleton();
}
return instance;
}
}
Dans le code ci-dessus, la méthode getInstance() n’est pas sûre pour les threads. Plusieurs threads peuvent y accéder en même temps. Pour les premiers threads lorsque la variable d’instance n’est pas initialisée, plusieurs threads peuvent entrer dans la boucle if et créer plusieurs instances. Cela va casser notre implémentation singleton.
Comment garantir la sécurité des threads dans une classe Singleton ?
Il existe trois façons de garantir la sécurité des threads.
- Créer la variable d’instance au moment du chargement de la classe.
Avantages:
- Sécurité des threads sans synchronisation
- Facile à implémenter
Inconvénients:
- Création anticipée de ressources qui pourraient ne pas être utilisées dans l’application.
- L’application cliente ne peut pas passer d’arguments, donc nous ne pouvons pas le réutiliser. Par exemple, avoir une classe singleton générique pour la connexion à la base de données où l’application cliente fournit les propriétés du serveur de base de données.
- Synchroniser la méthode getInstance().
Avantages:
- La sécurité du thread est garantie.
- L’application cliente peut transmettre des paramètres
- L’initialisation paresseuse est réalisée
Les inconvénients:
- Performances lentes en raison d’une surcharge de verrouillage.
- Synchronisation inutile qui n’est pas nécessaire une fois que la variable d’instance est initialisée.
- Utilisez un bloc synchronisé à l’intérieur de la boucle if et une variable volatile
Avantages:
- La sécurité du thread est garantie
- L’application cliente peut transmettre des arguments
- L’initialisation paresseuse est réalisée
- La surcharge de synchronisation est minimale et applicable uniquement pour les premiers threads lorsque la variable est nulle.
Inconvénients:
- Condition if supplémentaire
En examinant les trois façons d’assurer la sécurité des threads, je pense que la troisième option est la meilleure. Dans ce cas, la classe modifiée ressemblera à ceci :
package com.journaldev.designpatterns;
public class ASingleton {
private static volatile ASingleton instance;
private static Object mutex = new Object();
private ASingleton() {
}
public static ASingleton getInstance() {
ASingleton result = instance;
if (result == null) {
synchronized (mutex) {
result = instance;
if (result == null)
instance = result = new ASingleton();
}
}
return result;
}
}
La variable locale result
semble inutile. Mais elle est là pour améliorer les performances de notre code. Dans les cas où l’instance est déjà initialisée (la plupart du temps), le champ volatile n’est accédé qu’une seule fois (en raison de « return result; » au lieu de « return instance; »). Cela peut améliorer les performances globales de la méthode jusqu’à 25 pour cent. Si vous pensez qu’il existe de meilleures façons d’atteindre cela ou si la sécurité du thread est compromise dans l’implémentation ci-dessus, veuillez commenter et le partager avec nous tous.
Conseil Bonus
String n’est pas un très bon candidat pour être utilisé avec le mot-clé synchronisé. C’est parce qu’ils sont stockés dans un pool de chaînes et nous ne voulons pas verrouiller une chaîne qui pourrait être utilisée par un autre morceau de code. Donc j’utilise une variable d’objet. Apprenez-en davantage sur la synchronisation et la sécurité des threads en Java.
Vous pouvez consulter plus d’exemples Java depuis notre Dépôt GitHub.
Source:
https://www.digitalocean.com/community/tutorials/thread-safety-in-java-singleton-classes