Le modèle singleton est le plus simple à comprendre et le moyen le plus simple de le code rédigé dans le modèle de conception, mais il n'y a pas beaucoup de points de connaissances impliqués, il est donc souvent utilisé comme question d'entrevue. Généralement, les singletons sont écrits de cinq manières: paresseux, affamé, verrouillage à double vérification, classes internes statiques et énumération. Afin d'enregistrer le processus d'apprentissage, plusieurs méthodes d'écriture de singleton courantes ont été compilées ici.
Bronze 5: (chargé de paresseux, mais le fil n'est pas sûr)
Lorsqu'on leur a demandé de mettre en œuvre un modèle singleton, la première réaction de nombreuses personnes est d'écrire le code suivant, y compris les mêmes enseignements dans les manuels.
classe publique Singleton {instance privée de singleton statique; privé singleton () {} public static singleton getInstance () {if (instance == null) {instance = new singleton (); } return instance; }}Ce code est simple et simple et utilise le mode de chargement retardé, mais les threads ne sont pas sûrs. L'appel de la méthode getInstance () dans un environnement multi-thread peut entraîner la saisie des threads de plusieurs threads du bloc de code du programme de l'instruction IF.
Style paresseux: synchronisé (chargé de paresseux, en filetage, mais pas efficace)
Pour résoudre le problème ci-dessus, le moyen le plus simple est de définir la méthode GetInstance () à synchroniser.
classe publique Singleton {instance privée de singleton statique; private singleton () {} public static synchronisé singleton getInstance () {if (instance == null) {instance = new singleton (); } return instance; }}Bien qu'il soit en file d'attente et en retard, il n'est pas efficace. Car à tout moment, il ne peut y avoir qu'un seul thread appelant la méthode getInstance (). Cependant, l'opération synchronisée ne doit être nécessaire que lors du premier appel, c'est-à-dire lorsque l'objet d'instance Singleton est créé pour la première fois. Ce modèle ne provoque qu'un seul fil pour accéder à la méthode getInstance () à la fois même après la création du singleton, ce qui peut entraîner des problèmes de performance potentiels. Cela conduit à un serrure à double vérification.
Style affamé: champ final statique (non chargé de paresseux)
Cette méthode est très simple, car l'instance d'un singleton est déclarée finale statique et est initialisée lorsque la classe est chargée dans la mémoire pour la première fois, donc la création d'un objet d'instance est une file d'attente (garantie par l'implémentation JVM).
classe publique Singleton {// Initialiser l'instance privée de singleton final statique = new Singleton (); private singleton () {} public static singleton getInstance () {// singleton avec instance de retour statique d'usine; }}Ce n'est pas un mode de chargement paresseux, l'instance sera initialisée depuis le début après le chargement de la classe, même si le client n'appelle pas la méthode getInstance (). Cela conduira à certaines restrictions d'utilisation: par exemple, la création d'une instance singleton dépend des paramètres ou des fichiers de configuration. Avant getInstance (), une certaine méthode doit être appelée pour y régler des paramètres, afin que cette méthode d'écriture singleton ne soit pas utilisée. Des méthodes similaires incluent:
classe publique Singleton {public static final singleton instance = new singleton (); // singleton avec un champ final public Singleton privé () {}} // <Java efficace> Page 14 fait la différence entre les deuxVerrouillage à double vérification + volatile (chargement lazy, filefure, mais obscur)
Le modèle de verrouillage à double vérification est une méthode de verrouillage à l'aide de blocs synchrones. Les programmeurs l'appellent un verrouillage à double vérification car il y aura deux instances de contrôle == null, une fois en dehors du bloc de synchronisation et une fois à l'intérieur du bloc de synchronisation. Pourquoi devons-nous vérifier à nouveau dans le bloc de synchronisation? Étant donné que plusieurs threads peuvent entrer en dehors du bloc de synchronisation ensemble, si aucune vérification secondaire n'est effectuée dans le bloc de synchronisation, plusieurs objets d'instance seront générés.
public static singleton getSingleton () {if (instance == null) {// single vérifié synchronisé (singleton.class) {if (instance == null) {// instance double coché = new singleton (); }}} Instance de retour;}Ce code a l'air parfait, mais malheureusement, il est problématique. L'essentiel est l'instance de phrase = new Singleton (). Ce n'est pas une opération atomique. En fait, cette phrase dans JVM fait à peu près les 3 choses suivantes.
Cependant, il y a une optimisation de la réorganisation des instructions dans le compilateur JIT de JVM. En d'autres termes, l'ordre des deuxième et troisième étapes ci-dessus ne peut être garanti et l'ordre d'exécution final peut être 1-2-3 ou 1-3-2. S'il s'agit de ce dernier, il sera préempté par le thread 2 avant que l'exécution de 3 et 2 ne soit exécutée. Pour le moment, l'instance est déjà non nulle (mais non initialisée), donc Thread 2 renvoie directement l'instance, puis l'utilisera, puis signalera naturellement une erreur. Pour ce faire, nous devons déclarer la variable d'instance comme volatile.
Classe publique Singleton {instance privée de singleton statique volatile; // Déclare comme volatile privé singleton () {} public static singleton getingleton () {if (instance == null) {synchronisé (singleton.class) {if (instance == null) {instance = new singleton (); }} return instance; }}Cependant, il est important de noter qu'il y a encore des problèmes avec le verrouillage à double vérification des versions volatiles avant Java 1.5. Ce problème n'a été résolu que dans Java 1.5, vous pouvez donc utiliser volatile après cela.
Classe intérieure statique: IODH, support d'initialisation à la demande
Ce modèle combine les classes internes statiques de Java et les connaissances de verrouillage de synchronisation par défaut multithread de Java, et implémente intelligemment le chargement de latence et la sécurité des filetages.
classe publique Singleton {private singleton () {} classe statique privée LazyHolder {private static final singleton instance = new singleton (); } public static singleton getInstance () {// de wikipedia return LazyHolder.instance; }}Une classe intérieure statique est équivalente à la partie statique de sa classe extérieure. Ses objets ne dépendent pas d'objets de classe externe, ils peuvent donc être créés directement. Les classes internes statiques ne seront reproduites que lorsqu'elles seront utilisées pour la première fois.
Verrouillage de synchronisation par défaut multithread
Comme nous le savons tous, dans le développement multi-thread, afin de résoudre le problème de concurrence, il s'agit principalement d'utiliser synchronisé pour ajouter des mutex pour le contrôle de synchronisation. Mais dans certains cas, le JVM effectue déjà implicitement la synchronisation pour vous, et dans ces cas, il n'est pas nécessaire d'effectuer manuellement le contrôle de la synchronisation. Ces situations comprennent :
1. Lors de l'initialisation des données par un initialiseur statique (initialiseur sur un champ statique ou dans un bloc {} statique)
2. Lorsque vous accédez au champ final
3. Lors de la création d'un objet avant de créer un fil
4. Lorsque le thread peut voir l'objet, il traitera
Énumérer
À partir de Java 1.5, écrivez simplement un type d'énumération contenant un seul élément:
Singleton en énum public {instance;}Cette méthode est fonctionnellement similaire à la méthode du domaine public, mais elle est plus concise et fournit gratuitement un mécanisme de sérialisation, empêchant absolument plusieurs instanciations, même lorsqu'il est confronté à des attaques de sérialisation ou de réflexion complexes. Bien que cette approche n'ait pas été largement adoptée, les types d'énumération d'éléments uniques sont devenus le meilleur moyen de mettre en œuvre Singleton.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1. Quels sont les détails de la finale statique
2. L'initialisation de l'affectation est-elle au champ statique en séquence et au bloc de code statique?
3. Comment écrire un modèle singleton pour les classes internes statiques
4. Les exemples de l'analyse et de l'application des modèles de conception Java EE ont-ils vraiment un effet de chargement paresseux?
Ce qui précède est tout le contenu de cet article. J'espère que le contenu de cet article sera d'une aide à l'étude ou au travail de chacun. J'espère également soutenir plus Wulin.com!