public static synchronized MySingleton getInstance() { if (_instance==null) { _instance = new MySingleton(); } return _instance; }
6 Réponses :
1.Es-là un défaut avec la mise en œuvre ci-dessus de la getInstance Méthode? P> blockQuote>
Oui, le mot clé synchronisé doit également envelopper l'instruction IF. Si ce n'est pas alors deux ou plusieurs threads pourraient potentiellement passer au code de création. P>
2.Quelle est la différence entre les deux implémentations? P> blockQuote>
La deuxième mise en œuvre est correcte et de mon point de vue plus facile à comprendre. P>
Utilisation synchronisée au niveau de la méthode pour une méthode statique se synchronise sur la classe, c'est-à-dire ce que vous avez fait dans l'échantillon 1. Utilisation synchronisée au niveau de la méthode pour une méthode d'instance se synchronise sur l'instance d'objet. P>
@Op: Dans cette zone, vous trouverez quelque chose appelé "motif de verrouillage à double vérification". C'est là que vous vérifiez, trouvez la null, puis synchronisez, puis vérifiez à nouveau (au cas où les choses ont changé entre-temps), puis créez. Cela fonctionne dans de nombreuses langues, mais ne fonctionne pas dans Java i> Sauf si vous n'utilisez pas un champ code> volatile code> de l'instance, qui est «Way sur le dessus. Vous êtes préféré avec votre deuxième implémentation, en particulier avec les JVM récents qui gèrent de manière très efficace des blocs syncrhonisés. Plus de lecture ici: iBM.com/DeveloperWorks/library/j-JTP02244.html < / a>
@Op Re mon commentaire ci-dessus, j'aurais dû être plus clair: cela fonctionne dans de nombreux environnements i>, mais pas le JVM (sauf si vous n'utilisez pas un champ code> volatile code> ou son équivalent - Si cela - dans la langue utilisée). Clarification Parce que ces jours-ci, Java n'est qu'une des nombreuses langues qui compile jusqu'à Java Bytecode et s'exécute sur la JVM (et de la même manière - bien que plus rarement - il existe des compilateurs Java qui compilent le code de la machine et n'utilisent pas de JVM. ).
1.Es-là un défaut avec la mise en œuvre ci-dessus de la getInstance Méthode? P>
Cela ne fonctionne pas. Vous pouvez vous retrouver avec plusieurs instances de votre singleton. P>
2.Quelle est la différence entre les deux implémentations? P> blockquote>
Le second fonctionne, mais nécessite une synchronisation, ce qui pourrait ralentir le système lorsque vous avez beaucoup d'accès à la méthode à partir de différents threads. P>
La mise en œuvre correcte la plus simple: < / p>
xxx pré> plus court et meilleur (sérialisable en toute sécurité): p>
xxx pré> initialisation paresseux de singletons est un sujet qui attire l'attention
manière forte> hors de proportion avec son utilité pratique réelle (IMO discutant des complexités de verrouillage à double vérification, à laquelle votre exemple est la première étape, n'est rien qu'un concours pissant). P> Dans 99% de tous les cas, vous n'avez pas besoin d'une initialisation paresseuse du tout, ou le "init quand la classe est de la première référence" de Java est assez bon. Dans les 1% restants des cas, il s'agit de la meilleure solution: p>
xxx pré> blockQquote>
Enums ne sont pas réalisés paresseusement, bien que
Bon points Michael. J'aime votre implémentation directe.
On dirait que vous avez oublié le type et le mot-clé code> statique code> sur le membre _Instance code>. De plus, quel est le but de synchroniser la méthode code> getInstance code> si vous ne faites pas de paresseux-init? (Convenu que l'on a rarement besoin de paresseux init; mais dans ces cas où l'on fait ...)
On dirait que vous éditeriez comme je commentant. Il manque toujours le type, cependant.
@skaffman, @ t.j.: a obtenu l'approche énum confuse avec la classe de titulaire, corrigée maintenant
@Petar: l'a abandonné et l'a modifiée moi-même, ce que je n'aime pas normalement faire lorsque l'auteur d'origine est activement impliqué, mais ... cette partie est maintenant correcte.
@Michael: Cette "meilleure solution" impliquant l'énum ressemble à une abus grave enum.
@Michael: Plus je le regarde, plus je ne vois aucune raison de que cela soit un énumé plutôt que juste une classe. De toute façon, vous exploitez le chargeur de classe pour faire votre synchronisation pour vous (comme ce répondant quelques mois en arrière Stackoverflow.com/questions/878577/... ). C'est peut-être une approche valide (c'est certainement intéressant), cependant, je me poserais de la question de savoir si cela fonctionne mieux dans des situations du monde réel que de travailler via un membre code> code> ou simplement la synchronisation du getter et de vivre avec elle. Mais pas besoin de lancer enum code> dessus!
@ Michael- Je pense que nous devons avoir un constructeur privé pour empêcher l'instanciation directe de Singleton.
"Vous pouvez vous retrouver avec plusieurs instances de votre singleton." Le problème avec DCL est plus que cela, il est également possible de renvoyer des instances partiellement construites de l'objet à partir de la méthode (qui est probablement plus sévère dans certains cas que de créer deux instances).
@ T.J. Crowder: L'avantage massif de la solution Enum est qu'il assure à un niveau très bas que vous ne pouvez pas créer d'autres cas. Plus précisément, cela vous donne une sérialisation en toute sécurité et est restilent contre la réflexion. En tant qu'appel à l'autorité: c'est la solution favorisée par Joshua Block lors de la dernière édition de Java efficace.
Qu'en est-il de ceux qui utilisent des techniques d'injection de dépendance à des fins de test? Dans ce cas, il est définitivement éteint d'utiliser une instanciation paresseuse afin que les dépendances moquées puissent être injectées avant la version de la mise en œuvre de ces dépendances de la charge pendant les tests.
@ Liltitus27: Cela ressemble à un piratage légèrement sale lorsque vous n'avez pas de cadre d'injection de dépendance réel avec des configurations de test et de production complètement séparées.
Ne devrions-nous pas toujours utiliser le dernier mot clé lors de l'initialisation des classes Singleton. statique privé mysingleton _instance = nouvelle mySingleton (); devrait être privé statique finale mysingleton _instance = nouvelle mySingleton (); Final Assurez-vous que la classe Singleton est réellement initialisée avant tout l'accès. Corrigez-moi si je me trompe.
@ R.A.J: Vous avez tort - ce n'est pas ce que finale. La spécification JVM garantit qu'une classe est entièrement initialisée avant qu'elle ne soit utilisée (bien que vous puissiez saboter que, en appelant le code externe du constructeur et en passant ce code> à celui-ci). Qu'est-ce que
final code> est-ce que le champ d'instance ne peut pas être modifié après l'initialisation de la classe. Qui est sémantiquement correct ici, mais pas strictement nécessaire.
@Michaelborgwardt Stackoverflow.com/a/11307418/846970 est ce qui me confond. Si je comprends bien, ce que vous suggérez d'être, je n'ai pas besoin de vous inquiéter de la sécurité de l'initialisation lors de l'accès aux variables statiques d'une classe?
@Raj: HM, après avoir vérifié certaines références, on dirait que j'avais tort en ce qui concerne le code multithreadé et qu'il existe en fait un traitement spécial pour les variables finales introduites en 2004 avec JSR 133. Je vais ajouter le final < / Code> - Et merci de le pointer.
Le second est le fil sûr, mais il a la surcharge de synchronisée sur chaque appel, peu importe si l'instance est construite ou non. La première option a une faille majeure qu'il n'a pas de vérification si (_Instance == null) dans le bloc synchronisé pour éviter de créer deux instances. P>
Le premier est imparfait de deux manières. Comme les autres mentionnaient ici, plusieurs threads pourraient passer par
if (_instance==null) {
Les différentes approches des singletons paresseux-chargeurs sont discutées par Bob Lee dans
Chargement paresseux Singletons et l'approche "droite" est le Initialisation du titulaire de la demande (IODH) idiom qui nécessite Très peu de code et a une synchronisation zéro surhead. BOB Lee Expliquez également lorsqu'il veut charger paresseux un singleton (pendant les tests et le développement). Honnêtement, je ne suis pas convaincu qu'il y a un avantage énorme. p> p>
Je suggérerais la mise en œuvre suivante
public class MySingleTon { private static MySingleton obj; //private Constructor private MySingleTon() { } public static MySingleTon getInstance() { if(obj==null) { synchronized(MySingleTon.class) { if(obj == null) { obj = new MySingleTon(); } } } return obj; } }
Cela revêt toujours un verrouillage à double vérification et est donc toujours incorrect.
Stackoverflow.com/ Questions / 70689 / ...
Il y a un problème intrinqué avec une variante de votre premier code (une variation qui vérifie la nullité, d'abord en dehors de la synchronisation et la suivante à l'intérieur de la synchronisation). Cela a à voir avec la façon dont le compilateur et la JVM font des choses. Si vous êtes très intéressé, vous pouvez rechercher «Un problème de java d'initialisation à double vérification».
Vous êtes peut-être intéressé par ce célèbre papier sur "Verrouillage à double coffre" qui vient fondamentalement à la conclusion qu'il est cassé: aristeia.com/papers/ddj_jul_aug_2004_Revised.pdf
Vous pouvez également être intéressé par: CS.UMD.EDU/~PUGH /java/MemoryModel/doublecheckedLocking.html
@Michael DCL est sécurisé à partir du modèle de mémoire Java 5, tant que vous le faites correctement.