Maison  >  Article  >  Java  >  Comment résoudre les problèmes de sécurité des threads dans le modèle Java singleton ?

Comment résoudre les problèmes de sécurité des threads dans le modèle Java singleton ?

王林
王林avant
2023-05-09 19:28:061458parcourir

    1. Facteurs à prendre en compte lors de l'utilisation du multi-threading

    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

    2. Mode Singleton

    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

    1 Mode affamé

    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;
        }
    }

    2. Mode paresseux

    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 threads

    Résultats :Des problèmes de sécurité des threads se produisent lors de la première création de l'instance

    3 Mode paresseux (amélioré grâce à l'utilisation de la synchronisation)

    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 lock

    Résultat :Bien qu'il soit thread-safe, il est inefficace

    4 Mode paresseux (amélioré en utilisant le verrouillage à double vérification)

    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 :

    Comment résoudre les problèmes de sécurité des threads dans le modèle Java singleton ?

    3. volatile Principe

    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

    4. Problèmes d'expansion volatile (comprendre). )

    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!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer