Dans les programmes Java, il peut parfois être nécessaire de reporter certaines opérations d'initialisation d'objets à haute tête et n'est initialisé que lors de l'utilisation de ces objets. C'est ce qu'on appelle l'initialisation retardée ou le chargement paresseux
Regardez une initialisation de retard dangereuse:
Après que le thread A exécute 1, il constate que l'instance d'objet est nul et est prête à nouveau, tandis que le thread B est nouveau en premier, ce qui provoque une erreur.
Nous pouvons utiliser des verrous de synchronisation pour assurer l'exactitude:
Mais la synchronisation de toute la méthode est trop chère, et les gens ont proposé un verrouillage à double vérification:
Le verrouillage de synchronisation utilisé dans la plage minimale semble atteindre l'objectif en utilisant la double vérification, mais cela a un problème: lorsqu'un thread 4, le thread B 7 n'a pas encore été exécuté et le thread a détermine l'instance! = NULL. Le fil B 7 n'a pas encore été exécuté, alors pourquoi cela se produit-il?
Jetez un œil à l'implémentation clé sous-jacente de la nouvelle instance ():
En fait, il s'agit d'abord d'effectuer 1 mémoire d'allocation, puis d'initialiser l'objet et de définir l'instance. Ensuite, il y a une réorganisation ici, et l'ordre des 2 et 3 peut être remplacé:
Ainsi, lorsque B exécute toujours 7, A détermine à 4 que l'objet d'instance a été initialisé. Si l'instance est appelée avant Ctorinstance (mémoire) provoquera une erreur.
Il y a deux solutions:
1. Déclarer l'objet d'instance comme volatile, il interdit la réorganisation de 2 et 3
2. Utilisation d'une solution basée sur l'initialisation de la classe: le JVM effectuera l'initialisation de la classe à l'étape d'initialisation de la classe (c'est-à-dire une fois la classe chargée et avant son utilisation par le thread). exister
Lors de l'initialisation de la classe d'exécution, le JVM acquiert un verrou. Ce verrou peut synchroniser l'initialisation de la même classe par plusieurs threads
Nous constatons que le code d'implémentation du schéma basé sur l'initialisation des classes est plus simple. Mais le schéma de verrouillage à double vérification basé sur le volatile a un avantage supplémentaire: en plus de retarder l'initialisation des champs statiques, il peut également retarder l'initialisation des champs d'instance. L'initialisation des retards de champ réduit les frais généraux de l'initialisation des classes ou de la création d'instances, mais augmente les frais généraux d'accès aux champs qui sont retardés initialisés. La plupart du temps, l'initialisation normale est meilleure que l'initialisation retardée. Si vous avez vraiment besoin d'utiliser les champs d'initialisation tardive par filetage par exemple, veuillez utiliser le schéma d'initialisation de retard volatile décrit ci-dessus; Si vous avez vraiment besoin d'utiliser une initialisation tardive en filetage pour les champs statiques, veuillez utiliser le schéma d'initialisation basé sur la classe décrit ci-dessus.
Résumer
Ce qui précède est le code d'implémentation du verrouillage de double vérification Java introduit par l'éditeur. J'espère que ce sera utile à tout le monde. Si vous avez des questions, veuillez me laisser un message et l'éditeur répondra à tout le monde à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!