Le modèle singleton est l'un des 23 modèles de conception. C'est un modèle de conception relativement simple. Son but est de renvoyer le même objet quel que soit le nombre d'appels. Sa particularité est que le constructeur est privatisé.
Il est divisé en deux structures, l’une est le style de l’homme paresseux et l’autre est le style de l’homme affamé. Elles ont chacune leurs propres avantages et inconvénients. Commençons par le style de l’homme affamé. Le code est le suivant :
public class Single { private static Single single = new Single(); private Single() { } public Single getInstance() { return single } }
Le programme ci-dessus montre que même si notre objectif de charger le même objet a effectivement été atteint, un seul objet sera créé lors du chargement du programme. Lorsque cette classe a plusieurs méthodes de ce type, nous ne pouvons pas les utiliser. dans cet objet entraînera un gaspillage de mémoire. Ainsi, le modèle paresseux singleton est apparu. Le code est le suivant :
public class Single { private static Single = null; private Single() { } public Single getInstance() { if(single==null){ single = new Single( } return single;
De cette façon, l'objet ne sera nouveau que lorsque nous l'appellerons réellement, mais cela pose un problème.
Lorsque le deuxième morceau de code ci-dessus est appelé par deux threads lors de son premier chargement, deux objets différents seront générés, il n'est donc pas sécurisé pour les threads. À ce stade, vous penserez à ajouter un Lock, le code après le verrouillage. est la suivante :
public class Single { private static Single = null; private Single() { } public synchronisé Single getInstance() { if (single == null) { single = new Single( } return single;
Cela garantit la sécurité des threads, mais lorsque la méthode de verrouillage doit effectuer beaucoup de choses, l'appel de cette méthode prendra beaucoup de temps, ce qui est fatal au serveur, car si un thread continue d'appeler cette méthode, il n'y a aucun moyen de l'ajuster. d'autres threads, et le serveur sera bloqué. Ensuite, le code mis à niveau est le suivant :
public class Single { priate static Single single = null; private Single() { } public Single getInstance() { if (single == null) { synchronisé (Single.class) { single = new Single( } } return single; } }
Après une observation attentive, j'ai découvert qu'il n'y avait pas de verrouillage de cette manière. Lorsque deux threads arrivent à la méthode getInstance() en cas de jugement, l'un d'eux doit être bloqué une fois l'exécution de l'autre terminée, le thread bloqué sera bloqué. n'est plus Pour déterminer s'il est vide, un objet sera quand même créé, de cette façon, plusieurs objets seront générés, puis mis à niveau. Le code résultant est le suivant :
public class Single { private static Single single = null; private Single() { } public Single getInstance() { if (single == null) { synchronisé (Single.class) { if (single == null) { single = new Single (); } } } renvoie un seul ;
De cette façon, le problème ci-dessus ne se produira pas et il ne sera verrouillé qu'une seule fois, car lorsque la méthode est exécutée pour la deuxième fois, le jugement if sera ignoré et le single sera renvoyé directement. Il ne sera plus verrouillé. , et l'efficacité d'exécution sera très élevée.
Mais même ainsi, il y a toujours un problème, car nous ne pouvons pas être sûrs si l'objet reçoit d'abord une valeur dans la mémoire ou si l'objet est créé en premier, donc le deuxième programme peut obtenir un objet à moitié initialisé dans jdk1 après 5. , on peut utiliser le mot clé volatile pour éviter cette situation. Le code est le suivant :
public class Single { private static volatile Single single = null; private Single() { } public Single getInstance() { if (single == null) { synchronisé (Single.class) { if (single == null) { single = new Single(); } } } renvoie unique ;
Mais cette situation est rarement utilisée, je suis juste là pour apprendre, hehe.