Améliorer l'efficacité : L'utilisation du multi-threading consiste à utiliser pleinement les ressources du processeur et à améliorer l'efficacité des tâches
Sécurité des threads : La chose la plus fondamentale à propos l'utilisation du multithread est un problème de sécurité. Problèmes de sécurité des threads
Ainsi, lorsque nous concevons du code multithread, nous devons améliorer autant que possible l'efficacité de l'exécution des tâches tout en respectant la sécurité des threads
Donc :
Verrouillage à grain fin : moins de code de verrouillage, afin que d'autres codes puissent être exécutés simultanément
Considérez la sécurité des threads :
Le code qui n'exploite pas les variables partagées n'a aucun problème de sécurité
Pour lire les variables partagées, utilisez volatile pour modifier les variables
Pour écrire des variables partagées, utilisez synchronisé Lock
Le mode singleton peut garantir qu'il n'y a qu'une seule instance d'une certaine classe dans le programme sans créer plusieurs instances
Par exemple : DataSource (pool de connexions de données), une base de données n'en a besoin que d'une seule. objet pool de connexions
Le mode singleton est divisé en mode affamé et en mode paresseux
Le mode affamé crée des instances lorsque la classe est chargée
Cette méthode satisfait au threading Safe (JVM utilise le verrouillage en interne, c'est-à-dire plusieurs threads appellent des méthodes statiques, un seul thread est en compétition pour le verrou et termine la création, et n'est exécuté qu'une seule fois)
Code d'implémentation :
public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return instance; } }
Mode paresseux L'instance n'est pas créée lorsque la classe. est chargé, mais est créé lors de sa première utilisation
Code d'implémentation :
public class Singleton { private static Singleton instance = null; private Singleton(){ } public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
En observant le code ci-dessus, il n'y a pas de problème de sécurité des threads dans un seul thread, mais il y a une sécurité dans un environnement multithread. ?
Analyse :
Lorsque l'instance n'est pas créée, si plusieurs threads appellent la méthode getInstance, plusieurs instances peuvent être créées et il y a un problème de sécurité des threads
Mais une fois l'instance créée, les threads suivants appellent getInstance. La méthode n'aura pas de problèmes de sécurité des threadsRésultats :Des problèmes de sécurité des threads se produisent lors de la première création de l'instance
Nous utilisons la modification synchronisée, ????? ???️Le code est le suivant :
public class Singleton { private static Singleton instance = null; private Singleton(){ } public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
Quels sont les problèmes liés à l'implémentation de la sécurité des threads de cette manière ?
Analyse :
Nous utilisons une modification synchronisée sur la méthode, ce qui signifie qu'à chaque fois que la méthode est appelée, le verrouillage sera exécuté, mais l'instance ne doit être créée qu'une seule fois, c'est-à-dire une fois l'instance créée. créé, l'appel de la méthode doit encore rivaliser. Lock release lockRésultat :Bien qu'il soit thread-safe, il est inefficace
Apportez des modifications en fonction du. code ci-dessus :
Utilisez la détermination double if, réduisez la fréquence de verrouillage de la compétition
Utilisez volatile pour modifier l'instance
Code d'implémentation :
public class Singleton { private static volatile Singleton instance = null; private Singleton(){ } public static synchronized Singleton getInstance(){ if(instance == null){ //外层的if判断:如果实例被创建直接return,不让线程再继续竞争锁 //在没有创建实例时,多个线程已经进入if判断了 //一个线程竞争到锁,其他线程阻塞等待 synchronized (Singleton.class) { //内层的if判断,目的是让竞争失败的锁如果再次竞争成功的话判断实例是否被创建,创建释放锁return,没有则创建 if(instance == null){ instance = new Singleton(); } } } return instance; } }
Analyse de double if :
Jugement if externe : L'instance est créé une seule fois, lorsque l'instance a été créée. S'il n'y a pas besoin d'opérations ultérieures, retournez simplement directement
Le jugement interne if : Lorsque l'instance n'est pas créée, plusieurs threads se disputent le verrou en même temps. le thread entre en compétition avec succès et crée l'instance, et les autres threads qui échouent à la compétition se bloqueront et attendront. Lorsque le premier thread libère le verrou, ces threads défaillants continueront à rivaliser, mais l'instance a été créée, il est donc nécessaire d'effectuer la compétition. si jugement encore
Analyse du dessin, comme indiqué ci-dessous :
volatile assure la visibilité et l'ordre Au niveau Java, volatile est une opération sans verrouillage. Plusieurs threads peuvent lire volatile-. variables modifiées simultanément et les exécute en parallèle, ce qui est presque aussi efficace qu'une exécution sans verrouillage
modification volatile Parmi les variables, le CPU utilise le protocole de cohérence du cache pour garantir que les dernières données de la mémoire principale sont lues
Cohérence du cache : Si d'autres threads modifient les variables volatiles modifiées, les variables dans le cache CPU seront réinitialisées. Si elle n'est pas valide, pour faire fonctionner cette variable, vous devez la relire depuis la mémoire principale
Si volatile ne garantit pas l'ordre, y a-t-il un problème avec la façon dont sont écrits les verrous à double contrôle ?
A propos du nouvel objet, il est divisé en 3 instructions dans l'ordre :
(1) Allouer l'espace mémoire de l'objet
(2) Instancier l'objet
(3) Attribuer à la variable
La normale l'ordre d'exécution est (1) (2)(3), JVM peut optimiser et réorganiser l'ordre en (1)(3)(2)
Le résultat de cette réorganisation peut faire qu'une fois l'espace mémoire alloué, l'objet n'a pas encore été instancié et l'affectation est terminée.
Après cette mauvaise affectation, instance==null ne tient pas et le thread tiendra. l'instance d'instanciation inachevée. , l'utilisation de ses propriétés et méthodes provoquera des erreurs
Après avoir utilisé volatile pour garantir l'ordre :
.Lorsque le thread crée un nouvel objet, quel que soit l'ordre de (1)(2)(3), l'instance obtenue par le thread suivant est Dans le
CPU qui a été instancié, il existe un mécanisme de verrouillage au niveau du CPU basé sur des opérations de variables volatiles (il garantit que (1)(2)(3) sont tous exécutés, réécrits dans la mémoire principale, puis d'autres threads exécutent des opérations sur les variables)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!