Table des matières
Démarrage rapide
Le principe de ThreadLocal
Diagramme de classe associé à ThreadLocal
set
get
rrreee
Solution
Maison Java javaDidacticiel Comment utiliser la classe Java ThreadLocal

Comment utiliser la classe Java ThreadLocal

May 14, 2023 pm 06:49 PM
java threadlocal

    Comme le montre l'image :

    Comment utiliser la classe Java ThreadLocal

    Démarrage rapide

    Ensuite, nous utiliserons un exemple simple pour vous montrer l'utilisation de base de ThreadLocal

    package cuit.pymjl.thradlocal;
    
    /**
     * @author Pymjl
     * @version 1.0
     * @date 2022/7/1 10:56
     **/
    public class MainTest {
        static ThreadLocal<String> threadLocal = new ThreadLocal<>();
    
        static void print(String str) {
            //打印当前线程中本地内存中本地变量的值
            System.out.println(str + " :" + threadLocal.get());
            //清除本地内存中的本地变量
            threadLocal.remove();
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置线程1中本地变量的值
                    threadLocal.set("thread1 local variable");
                    //调用打印方法
                    print("thread1");
                    //打印本地变量
                    System.out.println("after remove : " + threadLocal.get());
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置线程1中本地变量的值
                    threadLocal.set("thread2 local variable");
                    //调用打印方法
                    print("thread2");
                    //打印本地变量
                    System.out.println("after remove : " + threadLocal.get());
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    Copier après la connexion

    Les résultats en cours sont tels qu'indiqués dans la figure montrée :

    Comment utiliser la classe Java ThreadLocal

    Le principe de ThreadLocal

    Diagramme de classe associé à ThreadLocal

    Jetons d'abord un coup d'œil à la structure du diagramme de classe de la classe associée à ThreadLocal, comme indiqué dans l'image :

    Comment utiliser la classe Java ThreadLocal

    On peut voir sur cette image qu'il existe un threadLocals et un ThreadLocals hérités dans la classe Thread, qui sont des variables de type ThreadLocalMap, et ThreadLocalMap est une Hashmap personnalisée. Par défaut, ces deux variables dans chaque thread sont nulles et elles sont créées uniquement lorsque le thread actuel appelle la méthode set ou get de ThreadLocal pour la première fois. En fait, les variables locales de chaque thread ne sont pas stockées dans l'instance ThreadLocal, mais dans la variable threadLocals du thread appelant. En d’autres termes, les variables locales de type ThreadLocal sont stockées dans des espaces mémoire de thread spécifiques. ThreadLocal est un shell d'outil qui place la valeur dans les threadLocals du thread appelant via la méthode set et la stocke lorsque le thread appelant appelle sa méthode get, il la retire de la variable threadLocals du thread actuel pour l'utiliser. Si le thread appelant ne se termine jamais, alors cette variable locale sera toujours stockée dans la variable threadLocals du thread appelant. Par conséquent, lorsque la variable locale n'est pas nécessaire, vous pouvez supprimer la variable locale des threadLocals du thread actuel en appelant le. Remove méthode de la variable ThreadLocal. De plus, pourquoi les threadLocals dans Thread sont-ils conçus comme une structure de carte ? Évidemment parce que chaque thread peut être associé à plusieurs variables ThreadLocal. Ensuite, jetons un coup d'œil au code source de Set, Get et Remove de ThreadLocal

    set

        public void set(T value) {
            // 1.获取当前线程(调用者线程)
            Thread t = Thread.currentThread();
            // 2.以当前线程作为key值,去查找对应的线程变量,找到对应的map
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                // 3.如果map不为null,则直接添加元素
                map.set(this, value);
            } else {
                // 4.否则就先创建map,再添加元素
                createMap(t, value);
            }
        }
    Copier après la connexion
        void createMap(Thread t, T firstValue) {
            /**
             * 这里是创建一个ThreadLocalMap,以当前调用线程的实例对象为key,初始值为value
             * 然后放入当前线程的Therad.threadLocals属性里面
             */
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    Copier après la connexion
        ThreadLocalMap getMap(Thread t) {
            //这里就是直接获取调用线程的成员属性threadlocals
            return t.threadLocals;
        }
    Copier après la connexion

    get

        public T get() {
            // 1.获取当前线程
            Thread t = Thread.currentThread();
            // 2.获取当前线程的threadlocals,即ThreadLocalMap
            ThreadLocalMap map = getMap(t);
            // 3.如果map不为null,则直接返回对应的值
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            // 4.否则,则进行初始化
            return setInitialValue();
        }
    Copier après la connexion

    Ce qui suit est le code de setInitialValuesetInitialValue的代码

    private T setInitialValue() {
        //初始化属性,其实就是null
        T value = initialValue();
        //获取当前线程
        Thread t = Thread.currentThread();
        //通过当前线程获取ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果map不为null,则直接添加元素
        if (map != null) {
            map.set(this, value);
        } else {
            //否则就创建,然后将创建好的map放入当前线程的属性threadlocals
            createMap(t, value);
        }
            //将当前ThreadLocal实例注册进TerminatingThreadLocal类里面
        if (this instanceof TerminatingThreadLocal) {
            TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
        }
        return value;
    }
    Copier après la connexion

    这里我需要补充说明一下TerminatingThreadLocal

    /**
     * A thread-local variable that is notified when a thread terminates and
     * it has been initialized in the terminating thread (even if it was
     * initialized with a null value).
     * 一个线程局部变量,
     * 当一个线程终止并且它已经在终止线程中被初始化时被通知(即使它被初始化为一个空值)。
     */
    Copier après la connexion

    Je dois en ajouter explications supplémentaires ici TerminatingThreadLocal. Cette classe est nouvelle dans jdk11 et n'existe pas dans jdk8, il n'y a donc aucune description pertinente de cette classe dans de nombreuses analyses de code source sur Internet. J'ai jeté un œil au code source de cette classe, et sa fonction devrait être d'éviter le problème des fuites de mémoire ThreadLocal (si vous êtes intéressé, vous pouvez vérifier le code source, et veuillez me corriger s'il y a des erreurs). Voici l'explication officielle :

         public void remove() {
             //如果当前线程的threadLocals 变量不为空, 则删除当前线程中指定ThreadLocal 实例的本地变量。
             ThreadLocalMap m = getMap(Thread.currentThread());
             if (m != null) {
                 m.remove(this);
             }
         }
    Copier après la connexion
    remove

    rrreee

    Summary

    Il y a une variable membre nommée threadLocals à l'intérieur de chaque thread. Le type de cette variable est Hash Map, où la clé est la variable ThreadLocal que nous avons définie cette référence, valeur. est la valeur que nous avons définie à l'aide de la méthode set. Les variables locales de chaque thread sont stockées dans la propre variable de mémoire du thread threadLocals. Si le thread actuel ne meurt jamais, ces variables locales existeront toujours, cela peut donc provoquer un débordement de mémoire. Par conséquent, n'oubliez pas d'appeler la méthode Remove de ThreadLocal pour la supprimer après. utiliser. Variables locales dans threadLocals correspondant au thread.

    Fuite de mémoire ThreadLocal

    Pourquoi une fuite de mémoire se produit-elle ?

    ThreadLocalMap utilise la référence faible de ThreadLocal comme clé. Si un ThreadLocal n'a pas de référence forte externe pour s'y référer, alors le ThreadLocal sera inévitablement recyclé lors du GC du système De cette façon, une entrée avec un null. key apparaîtra dans le ThreadLocalMap , il n'y a aucun moyen d'accéder à la valeur de ces entrées avec des clés nulles Si le fil de discussion en cours continue à se terminer, les valeurs de ces entrées avec des clés nulles auront toujours une chaîne de référence forte : Thread Ref -> Thread - > ThreaLocalMap -> La valeur de l'entrée ne peut jamais être recyclée, provoquant une fuite de mémoire.

    En fait, cette situation a été prise en compte dans la conception de ThreadLocalMap, et quelques mesures de protection ont été ajoutées : toutes les valeurs avec des clés nulles dans le thread ThreadLocalMap seront effacées lors de get(), set() et delete () de ThreadLocal. Cependant, ces mesures préventives passives ne garantissent pas qu'il n'y aura pas de fuites de mémoire :
    • L'utilisation de ThreadLocal statique prolonge le cycle de vie de ThreadLocal, ce qui peut entraîner des fuites de mémoire
    • L'allocation utilise ThreadLocal et n'appelle plus get( ), set(), remove(), cela provoquera des fuites de mémoire

    Pourquoi utiliser des références faibles ?

    Puisque nous savons tous que l'utilisation de références faibles entraînera des fuites de mémoire ThreadLocalMap, pourquoi les responsables utilisent-ils encore des références faibles au lieu de références fortes ? Cela commence par la différence entre utiliser des références faibles et des références fortes : 🎜
    • Si vous utilisez des références fortes : nous savons que le cycle de vie de ThreadLocalMap est fondamentalement le même que le cycle de vie de Thread. Si le thread actuel n'est pas terminé, alors ThreadLocalMap ne sera jamais recyclé par GC et ThreadLocalMap détient une forte référence. référence à ThreadLocal, alors ThreadLocal Il ne sera pas recyclé. Lorsque le cycle de vie du thread est long, s'il n'est pas supprimé manuellement, cela provoquera une accumulation de kv, ce qui entraînera un MOO

    • Si vous utilisez des références faibles : objets dans des références faibles. avoir une période de déclaration courte, car dans le système Pendant le GC, tant qu'une référence faible est trouvée, l'objet sera recyclé, qu'il y ait ou non suffisamment d'espace sur le tas. Lorsque la référence forte de ThreadLocal est recyclée, la référence faible détenue par ThreadLocalMap sera également recyclée. Si kv n'est pas supprimé manuellement, cela provoquera une accumulation de valeur et conduira également à OOM

    . l'utilisation de références faibles peut au moins garantir que le MOO ne sera pas causé par l'accumulation de clés de carte et que la valeur correspondante peut être effacée lors du prochain appel via les méthodes Remove, Get et Set. On peut voir que la cause première des fuites de mémoire ne réside pas dans les références faibles, mais que le cycle de vie de ThreadLocalMap est aussi long que celui de Thread, provoquant une accumulation

    Solution

    Puisque la racine du problème est l'accumulation de valeurs. provoquant du MOO, nous pouvons alors prescrire le bon médicament et nous assurer qu'il est utilisé après chaque utilisation. Il suffit d'appeler la méthode remove() de ThreadLocal pour le nettoyer.

    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 de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

    Outils d'IA chauds

    Undresser.AI Undress

    Undresser.AI Undress

    Application basée sur l'IA pour créer des photos de nu réalistes

    AI Clothes Remover

    AI Clothes Remover

    Outil d'IA en ligne pour supprimer les vêtements des photos.

    Undress AI Tool

    Undress AI Tool

    Images de déshabillage gratuites

    Clothoff.io

    Clothoff.io

    Dissolvant de vêtements AI

    AI Hentai Generator

    AI Hentai Generator

    Générez AI Hentai gratuitement.

    Article chaud

    R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
    1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. Meilleurs paramètres graphiques
    1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
    Will R.E.P.O. Vous avez un jeu croisé?
    1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

    Outils chauds

    Bloc-notes++7.3.1

    Bloc-notes++7.3.1

    Éditeur de code facile à utiliser et gratuit

    SublimeText3 version chinoise

    SublimeText3 version chinoise

    Version chinoise, très simple à utiliser

    Envoyer Studio 13.0.1

    Envoyer Studio 13.0.1

    Puissant environnement de développement intégré PHP

    Dreamweaver CS6

    Dreamweaver CS6

    Outils de développement Web visuel

    SublimeText3 version Mac

    SublimeText3 version Mac

    Logiciel d'édition de code au niveau de Dieu (SublimeText3)

    Nombre parfait en Java Nombre parfait en Java Aug 30, 2024 pm 04:28 PM

    Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

    Weka en Java Weka en Java Aug 30, 2024 pm 04:28 PM

    Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

    Numéro de Smith en Java Numéro de Smith en Java Aug 30, 2024 pm 04:28 PM

    Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

    Questions d'entretien chez Java Spring Questions d'entretien chez Java Spring Aug 30, 2024 pm 04:29 PM

    Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

    Break or Return of Java 8 Stream Forach? Break or Return of Java 8 Stream Forach? Feb 07, 2025 pm 12:09 PM

    Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

    Horodatage à ce jour en Java Horodatage à ce jour en Java Aug 30, 2024 pm 04:28 PM

    Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

    Programme Java pour trouver le volume de la capsule Programme Java pour trouver le volume de la capsule Feb 07, 2025 am 11:37 AM

    Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

    Comment exécuter votre première application Spring Boot dans Spring Tool Suite? Comment exécuter votre première application Spring Boot dans Spring Tool Suite? Feb 07, 2025 pm 12:11 PM

    Spring Boot simplifie la création d'applications Java robustes, évolutives et prêtes à la production, révolutionnant le développement de Java. Son approche "Convention sur la configuration", inhérente à l'écosystème de ressort, minimise la configuration manuelle, allo

    See all articles