当前位置:网站首页>9. Parler de threadlocal

9. Parler de threadlocal

2022-06-11 12:13:00 Shi xiaozan

1、ThreadLocalIntroduction

1.1、Quelques questions d'entrevue

ThreadLocalMoyenneThreadLocalMapStructure des données et relations?

ThreadLocalDekeyC'est une faible référence,C'est pourquoi??

ThreadLocalUne fuite de mémoire.?

ThreadLocalPourquoi ajouter à la fin du milieuremoveMéthodes?

......

1.2、Qu'est - ce que c'est?

Un peu de traduction.: 

ThreadLocalFournir des variables locales de thread.Ces variables sont différentes des variables normales,Parce que chaque fil accèdeThreadLocalPar exemple(Par songetOusetMéthodes) Ils ont tous leurs propres、Copie de la variable initialisée indépendamment .ThreadLocalLes instances sont généralement des champs statiques privés dans une classe,Le but de l'utiliser est de rendre l'état(Par exemple,UtilisateursIDOu affairesID)Associé à un thread.

1.3、Que puis - je faire

 Réalisation Chaque thread a sa propre copie de la variable locale (Utilisez vos propres variables pour ne pas déranger les autres,Ne pas partager avec les autres,Tout le monde a sa part.,Un pour chaque personne), 

La solution principale est de lier chaque thread à sa propre valeur,En utilisantget()Etset()Méthodes,Obtient la valeur par défaut ou change sa valeur à la valeur de la copie enregistrée par le thread courant pour éviter les problèmes de sécurité du thread. 

1.4、apiIntroduction

1.4、DehelloworldAllez.

1.4.1、 Sur la base des ventes totales , Faciliter les statistiques de planification pour les entreprises du Groupe

Les hommes se disputent

package com.atguigu.juc.tl;





class MovieTicket

{

    int number = 50;



    public synchronized void saleTicket()

    {

        if(number >0)

        {

            System.out.println(Thread.currentThread().getName()+"\t"+"---Ventes: "+(number--));

        }else{

            System.out.println("----C'est vendu.");

        }

    }

}





/**

 * @auther zzyy

 * @create 2021-03-23 15:03

 * 1   Trois chefs d'orchestre ont vendu 50 Billetterie , La quantité totale est suffisante ,Manger de la soupe de riz, Le chef d'orchestre reçoit un salaire mensuel fixe tous les mois 

 *

 * 2   Manger au four , Les ventes se font elles - mêmes ,Des vêtements et de la nourriture

 */

public class ThreadLocalDemo

{

    public static void main(String[] args)

    {

        MovieTicket movieTicket = new MovieTicket();

        

        for (int i = 1; i <=3; i++) {

            new Thread(() -> {

                for (int j = 1; j <=20; j++) {

                    movieTicket.saleTicket();

                }

            },String.valueOf(i)).start();

        }



    }

}



Résultats des opérations:

1---Ventes: 50

1---Ventes: 49

1---Ventes: 48

...

1---Ventes: 33

1---Ventes: 32

1---Ventes: 31

2---Ventes: 30

2---Ventes: 29

....

2---Ventes: 12

2---Ventes: 11

3---Ventes: 10

...

3---Ventes: 1

----C'est vendu.

...

----C'est vendu.

1.4.2、 Les exigences ci - dessus ont changé ...

Ne pas participer au calcul de la somme , J'espère qu'ils mangeront séparément , Chacun avec une Commission de vente , Statistiques au singulier

Comme un logiciel de recherche de chambre , Chaque vente intermédiaire a son propre indicateur de ventes , C'est mon propre , Ne pas mélanger avec les autres

Tout le monde est en sécurité

package com.atguigu.juc.tl;



class House

{





    ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);

    public void saleHouse()

    {

        Integer value = threadLocal.get();

        ++value;

        threadLocal.set(value);

    }

    

}



public class ThreadLocalDemo

{

    public static void main(String[] args)

    {

        

        House house = new House();



        new Thread(() -> {

            try

            {

                for (int j = 1; j <=3; j++) {

                    house.saleHouse();

                }

                System.out.println(Thread.currentThread().getName()+"\t"+"---Vendre: "+house.threadLocal.get());

            }catch (Exception e){

                e.printStackTrace();

            }finally {

                house.threadLocal.remove(); // Si vous ne nettoyez pas les personnalisations  ThreadLocal  Variables,Peut affecter la logique opérationnelle ultérieure et causer des problèmes tels que des fuites de mémoire

            }

        },"t1").start();



        new Thread(() -> {

            try

            {

                for (int j = 1; j <=2; j++) {

                    house.saleHouse();

                }

                System.out.println(Thread.currentThread().getName()+"\t"+"---Vendre: "+house.threadLocal.get());

            }catch (Exception e){

                e.printStackTrace();

            }finally {

                house.threadLocal.remove();

            }

        },"t2").start();



        new Thread(() -> {

            try

            {

                for (int j = 1; j <=5; j++) {

                    house.saleHouse();

                }

                System.out.println(Thread.currentThread().getName()+"\t"+"---Vendre: "+house.threadLocal.get());

            }catch (Exception e){

                e.printStackTrace();

            }finally {

                house.threadLocal.remove();

            }

        },"t3").start();

        

        System.out.println(Thread.currentThread().getName()+"\t"+"---Vendre: "+house.threadLocal.get());

        

    }

}



Résultats des opérations:

t1---Vendre: 3

t2---Vendre: 2

main---Vendre: 0

t3---Vendre: 5

1.5、 Résumé par le code ci - dessus

Parce que chaque Thread Il y en a un à l'intérieur.Copie de l'Instance Et cette copie n'est utilisée que par le thread courant lui - même

Puisque les autres Thread Inaccessible,Alors il n'y a pas de problème de partage multithreadé.

Définir uniformément les valeurs initiales, Mais chaque thread modifie cette valeur indépendamment l'un de l'autre

Un mot.: Comment ne pas se battre

1 AdhésionsynchronizedOuLock Contrôler l'ordre d'accès aux ressources

2 Une personne.,Tout le monde va bien, Pas besoin de voler

2、De AliThreadLocalDébut de la spécification

2.1、Non Thread - SAFESimpleDateFormat

Traduction ci - dessus :SimpleDateFormat Le format de date dans n'est pas synchronisé .Recommandations(Suggestion) Créer une instance de format distincte pour chaque thread .Si plusieurs Threads accèdent à un format en même temps,Il doit être synchronisé à l'extérieur. 

Écrire des classes d'outils temporels ,En général Variable membre statique ,Je ne sais pas., Les dangers de l'écriture Multithread ! 

Discutez en classe SimpleDateFormatProblème de thread non sécurisé,Et la solution.  

package com.atguigu.juc.tl;



import java.text.SimpleDateFormat;

import java.util.Date;



/**

 * @author shizan

 * @Classname DateUtis

 * @Description TODO

 * @Date 2022/6/7 4:40 Après - midi

 */

public class DateUtils {



    public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");



    /**

     *  Utilisation dans un environnement simulé et simultané  SimpleDateFormat De parse  La méthode convertit la chaîne en  Date Objet

     * @param stringDate

     * @return

     * @throws Exception

     */

    public static Date parseDate(String stringDate) throws Exception {

        return sdf.parse(stringDate);

    }



    public static void main(String[] args) throws Exception {

        for (int i = 1; i <= 30; i++) {

            new Thread(() -> {

                try {

                    System.out.println(DateUtils.parseDate("2020-11-11 11:11:11"));

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }, String.valueOf(i)).start();

        }

    }

}

Conclusion de l'analyse du code source:

SimpleDateFormatIl y en a un à l'intérieur de la classeCalendarRéférence de l'objet, Il est utilisé pour stocker et ceci SimpleDateFormat Informations relatives à la date ,Par exemplesdf.parse(dateStr),sdf.format(date) Ce genre de paramètre de méthode est lié à la date d'entrée String,DateAttendez un peu!, Tout est entre les mains de Calendar Référence à stocker .Cela pose un problème Si votreSimpleDateFormatC'est ça.staticDe, Tant de choses.thread Et ça sera partagé entre SimpleDateFormat, Et partager ça CalendarRéférences. 

2.2、Résolution1

Oui.SimpleDateFormat Défini comme une variable locale .

Inconvénients: Chaque fois qu'une méthode est appelée, une SimpleDateFormatObjet, La méthode est terminée et recyclée comme déchet .

package com.atguigu.juc.tl;



import java.text.SimpleDateFormat;

import java.util.Date;



/**

 * @author shizan

 * @Classname DateUtis

 * @Description TODO

 * @Date 2022/6/7 4:40 Après - midi

 */

public class DateUtils {





    public static void main(String[] args) throws Exception {

        for (int i = 1; i <= 30; i++) {

            new Thread(() -> {

                try {

                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                    System.out.println(sdf.parse("2020-11-11 11:11:11"));

                    sdf = null;

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }, String.valueOf(i)).start();

        }

    }

}

2.3、Résolution2

ThreadLocal,Aussi appelé thread local variable ou thread local storage

package com.atguigu.juc.tl;



import java.text.SimpleDateFormat;

import java.util.Date;



/**

 * @author shizan

 * @Classname DateUtis

 * @Description TODO

 * @Date 2022/6/7 4:40 Après - midi

 */

public class DateUtils {

    private static final ThreadLocal<SimpleDateFormat> sdf_threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));



    /**

     * ThreadLocal Assurez - vous que chaque thread a son propre SimpleDateFormat Objet de,Il n'y a donc naturellement aucun problème de concurrence.

     *

     * @param stringDate

     * @return

     * @throws Exception

     */

    public static Date parseDateTL(String stringDate) throws Exception {

        return sdf_threadLocal.get().parse(stringDate);

    }



    public static void main(String[] args) throws Exception {

        for (int i = 1; i <= 30; i++) {

            new Thread(() -> {

                try {

                    System.out.println(DateUtils.parseDateTL("2020-11-11 11:11:11"));

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }, String.valueOf(i)).start();

        }

    }

}

2.4、Autres

① Verrouillage

② No3 Fang Time Base

3、ThreadLocalAnalyse des sources

3.1、Thread,ThreadLocal,ThreadLocalMap Relations

ThreadEtThreadLocal

ThreadLocalEtThreadLocalMap

All Résumé général des trois

threadLocalMap En fait, c'est un threadLocalExemple:key, Tout objet est valueDeEntryObjet.

Quand nous sommesthreadLocalAffectation des variables, En fait, à l'heure actuelle threadLocalExemple:key,La valeur est:valueDeEntryPar làthreadLocalMapStockage intermédiaire 

3.2、Petit résumé

Une approximation peut être interprétée comme :   

ThreadLocalMap C'est littéralement une préservation ThreadLocal Objet map( En fait, ThreadLocal Pour Key) , Mais après deux couches d'emballage ThreadLocal Objet:   

JVM Maintenance interne d'une version threadée Map<Thread,T>( Adoption ThreadLocal Objet set Méthodes,Il s'avère que ThreadLocal L'objet lui - même key ,C'est parti. ThreadLoalMap Moyenne ) , Chaque fil utilise ceci T Quand,Utilisez le fil courant pour Map À l'intérieur., De cette façon, chaque thread a sa propre variable indépendante ,Une personne.,Les conditions de concurrence ont été complètement éliminées,Variable absolument sûre en mode simultané.   

4、ThreadLocalProblème de fuite de mémoire

4.1、 En commençant par les questions d'examen d'Ali

4.2、Qu'est - ce qu'une fuite de mémoire

La mémoire utilisée par l'objet ou la variable qui n'est plus utilisée ne peut pas être récupérée,C'est une fuite de mémoire..

4.3、 Qui a causé le malheur ?

4.3.1、why?

4.3.2、Forte citation、Référence souple、Faible référence、 Qu'est - ce que les références virtuelles, respectivement ?

4.3.2.1、Regarde en arrièreThreadLocalMap

ThreadLocalMap Avec WeakReference    

ThreadLocalMap C'est littéralement une préservation ThreadLocal Objet map( En fait, c'est comme ça que Key) , Mais après deux couches d'emballage ThreadLocal Objet:   

( 1 ) La première couche d'emballage est utilisée WeakReference<ThreadLocal<?>> Oui. ThreadLocal L'objet devient un Objets faiblement référencés;   

( 2 ) La deuxième couche d'emballage définit une classe spécifique Entry Pour étendre WeakReference<ThreadLocal<?>> ;   

4.3.2.2、Structure générale

Java Utilisation autorisée de la technologie finalize() Méthode faire le nettoyage nécessaire avant que le collecteur d'ordures nettoie l'objet de la mémoire.   

4.3.2.3、Forte citation( Mode de support par défaut ) 

Quand il n'y a pas assez de mémoire,JVMCommencer la collecte des ordures,Pour les objets fortement référencés, Même si c'est arrivé.OOMEt l'objet ne sera pas recyclé , La mort ne prend pas

  

Les références fortes sont nos références d'objets ordinaires les plus courantes,Tant qu'il y a une forte référence à un objet,Pour montrer que l'objet“Vivant.”,Le collecteur d'ordures ne touche pas ce genre d'objet.In Java La citation la plus courante est forte,Assigner un objet à une variable de référence,Cette variable de référence est une référence forte.Lorsqu'un objet est référencé par une variable fortement référencée,Il est accessible,Il ne peut pas être recyclé par un mécanisme de collecte des ordures, Même si cet objet ne sera jamais utiliséJVMNi recyclé. .Par conséquent, une forte référence estJavaUne des principales causes des fuites de mémoire. 

  

Pour un objet normal,S'il n'y a pas d'autres relations de référence,Tant que le champ d'application de la référence est dépassé ou explicitement en conséquence(Fort.)La référence est assignée à null, 

On pense généralement qu'ils peuvent être ramassés par les ordures(Bien sûr, le moment exact du recyclage dépend de la stratégie de collecte des ordures). 

package com.atguigu.juc.tl;



import java.util.concurrent.TimeUnit;



/**

 * @author shizan

 * @Classname ReferenceDemoCopy

 * @Description TODO

 * @Date 2022/6/7 5:13 Après - midi

 */

 class MyObject

{

    // En général, cette méthode fonctionne sans , Pour expliquer gc, Montrer aux élèves 

    @Override

    protected void finalize() throws Throwable

    {

        System.out.println("------------- gc ,finalize() invoked");

    }

}

public class ReferenceDemoCopy {



    public static void main(String[] args) {

        MyObject myObject = new MyObject();//Par défaut,Forte citation, Ne pas lâcher prise après la mort 

        System.out.println("gc before: "+myObject);



        myObject = null;

        System.gc();// Ouverture manuelle du rapport GcRecyclage.

        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }



        System.out.println("gc after: "+myObject);

    }

}



Résultats des opérations:

gc before: [email protected]

------------- gc ,finalize() invoked

gc after: null

  

4.3.2.4、Référence souple

Les références douces sont des références relativement fortes qui affaiblissent certaines références ,J'en ai besoin.java.lang.ref.SoftReferenceClasse pour implémenter,Les objets peuvent être exemptés de la collecte des ordures. 

  

Pour les objets qui n'ont que des références douces, 

          Quand le système a assez de mémoire       Ça ne va pas     Recyclé, 

          Lorsque le système est hors de mémoire          Oui.     Recyclé. 

Les références douces sont généralement utilisées dans les programmes sensibles à la mémoire,Par exemple, la mise en cache est utile pour les références douces, Gardez - le quand il y a assez de mémoire.,Recycler si ce n'est pas suffisant! 

package com.atguigu.juc.tl;



import java.lang.ref.SoftReference;

import java.util.concurrent.TimeUnit;



/**

 * @author shizan

 * @Classname ReferenceDemoCopy

 * @Description TODO

 * @Date 2022/6/7 5:13 Après - midi

 */

class MyObject

{

    // En général, cette méthode fonctionne sans , Pour expliquer gc, Montrer aux élèves 

    @Override

    protected void finalize() throws Throwable

    {

        System.out.println("------------- gc ,finalize() invoked");

    }

}

public class ReferenceDemoCopy {



    public static void main(String[] args) {



        SoftReference<MyObject> softReference = new SoftReference<>(new MyObject());//Référence souple



        //Quand nous n'avons pas assez de mémoire, soft Une situation qui pourrait être recyclée, Définir la taille de notre mémoire : -Xms10m -Xmx10m

        System.out.println("gc beforeAssez de mémoire: "+softReference.get());



        System.gc();// Ouverture manuelle du rapport GcRecyclage.

        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }





        //Définir les paramètres-Xms10m -Xmx10m

        System.out.println("gc before: "+softReference.get());



        try

        {

            byte[] bytes = new byte[9 * 1024 * 1024];

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            System.out.println("-----gc afterPas assez de mémoire: "+softReference.get());

        }

    }

}



Résultats des opérations:



Non.-Xms10m -Xmx10m Paramètres,Assez de mémoire

gc beforeAssez de mémoire: [email protected]

gc before: [email protected]

-----gc afterPas assez de mémoire: [email protected]



Plus -Xms10m -Xmx10mParamètres,Pas assez de mémoire

gc beforeAssez de mémoire: [email protected]

gc before: [email protected]

-----gc afterPas assez de mémoire: null

------------- gc ,finalize() invoked

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at com.atguigu.juc.tl.ReferenceDemoCopy.main(ReferenceDemoCopy.java:31)

4.3.2.5、Faible référence

Les références faibles nécessitentjava.lang.ref.WeakReferenceClasse pour implémenter,Il a une durée de vie plus courte que les références douces, 

Pour les objets avec des références faibles,Dès que le mécanisme de collecte des ordures fonctionne,Peu importeJVMEst assez d'espace mémoire pour,Récupère la mémoire utilisée par cet objet.  

package com.atguigu.juc.tl;



import java.lang.ref.SoftReference;

import java.lang.ref.WeakReference;

import java.util.concurrent.TimeUnit;



/**

 * @author shizan

 * @Classname ReferenceDemoCopy

 * @Description TODO

 * @Date 2022/6/7 5:13 Après - midi

 */

class MyObject

{

    // En général, cette méthode fonctionne sans , Pour expliquer gc, Montrer aux élèves 

    @Override

    protected void finalize() throws Throwable

    {

        System.out.println("------------- gc ,finalize() invoked");

    }

}

public class ReferenceDemoCopy {



    public static void main(String[] args) {

        WeakReference<MyObject> weakReference = new WeakReference(new MyObject());

        System.out.println("gc before: "+weakReference.get());



        System.gc();// Ouverture manuelle du rapport GcRecyclage.

        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }



        System.out.println("gc after: "+weakReference.get());

    }

}

Scénarios applicables aux références douces et faibles

Si une application doit lire beaucoup d'images locales:  

     *     Si l'image est lue à partir du disque dur à chaque fois qu'elle est lue, les performances peuvent être gravement affectées , 

     *     Si vous chargez tout en mémoire en même temps, il peut causer un débordement de mémoire .  

L'utilisation d'une référence souple à ce stade peut résoudre ce problème. 

  

  L'idée de conception est:Avec unHashMapPour sauvegarder la relation de cartographie entre le chemin de l'image et la référence douce associée à l'objet d'image correspondant,Quand il n'y a pas assez de mémoire,JVMRécupère automatiquement l'espace occupé par ces objets d'image mis en cache,Pour éviter efficacementOOMLa question de. 

Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); 

4.3.2.6、Référence virtuelle

 Les références virtuelles nécessitentjava.lang.ref.PhantomReferenceClasse pour implémenter. 

  

Comme son nom l'indique, C'est un faux. ,Contrairement à plusieurs autres références,Une référence virtuelle ne détermine pas le cycle de vie d'un objet. 

Si un objet ne contient que des références virtuelles,C'est comme s'il n'y avait pas de référence.,Peut être recyclé par un collecteur d'ordures à tout moment , 

Il ne peut pas être utilisé seul ou accéder à des objets par lui, Les références virtuelles doivent être dans la file d'attente des références (ReferenceQueue)Utilisation conjointe. 

  

La fonction principale de la référence virtuelle est de suivre l'état de l'objet recyclé par les ordures.  Simplement pour s'assurer que l'objet est finalizePlus tard,Un mécanisme pour faire quelque chose.  PhantomReferenceDegetLes méthodes reviennent toujoursnull ,Impossible d'accéder à l'objet de référence correspondant. 

Ce qui est important, c'est que: Indique qu'un objet est entré dans finalizationPhase,Peut êtregcRecyclage, Pour réaliser un rapport finalization Mécanismes plus souples pour les opérations de recyclage . 

En d'autres termes,,Définir le seul but de l'Association de référence virtuelle,C'est quand cet objet est recyclé par le collecteur pour recevoir une notification système ou ajouter un traitement ultérieur.

Méthode de construction:

File d'attente de référence

Je dois être sauvegardé dans la file d'attente de référence avant d'être recyclé . 

package com.atguigu.juc.tl;



import java.lang.ref.*;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.TimeUnit;



/**

 * @author shizan

 * @Classname ReferenceDemoCopy

 * @Description TODO

 * @Date 2022/6/7 5:13 Après - midi

 */



class MyObject

{

    // En général, cette méthode fonctionne sans , Pour expliquer gc, Montrer aux élèves 

    @Override

    protected void finalize() throws Throwable

    {

        System.out.println("------------- gc ,finalize() invoked");

    }

}

public class ReferenceDemoCopy {



    public static void main(String[] args) {



        ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>();

        PhantomReference<MyObject> phantomReference = new PhantomReference<>(new MyObject(),referenceQueue);

        System.out.println(phantomReference.get());



        List<byte[]> list = new ArrayList<>();



        new Thread(() -> {

            while (true)

            {

                list.add(new byte[1 * 1024 * 1024]);

                try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }

                System.out.println(phantomReference.get());

            }

        },"t1").start();



        new Thread(() -> {

            while(true)

            {

                Reference<? extends MyObject> poll = referenceQueue.poll();

                if (poll != null) {

                    System.out.println("------ Il y a des objets virtuels dans la file d'attente ");

                }

            }

        },"t2").start();



        //Pause pendant quelques secondes

        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }





    }

}

4.3.2.7、GCRoots Et quatre petites citations

4.3.3、Relations

ChaqueThreadL'objet maintient unThreadLocalMapRéférences 

ThreadLocalMap- Oui.ThreadLocalClasse interne,AvecEntryPour le stockage 

AppelezThreadLocalDeset()La méthode,En fait, c'est versThreadLocalMapSetPoint,key- Oui.ThreadLocalObjet,ValeurValue C'est l'objet passé  

AppelezThreadLocalDeget()La méthode,En fait, c'est versThreadLocalMapObtenir la valeur,key- Oui.ThreadLocalObjet 

ThreadLocalNe stocke pas les valeurs en soi, C'est juste lui - même en tant que keyPour que les threadsThreadLocalMapAccèsvalue,C'est ce principe.,Alors...ThreadLocalCapable de réaliser“Isolement des données”,Obtient la valeur de la variable locale pour le thread courant,Non affecté par d'autres fils~ 

4.4、Pourquoi utiliser des références faibles? Pas besoin de ?

public void function01() {

    ThreadLocal tl = new ThreadLocal<Integer>();  //line1

    tl.set(2021);  //line2

    tl.get();  //line3

}

line1Un nouveauThreadLocalObjet,t1 Est une référence forte à cet objet ;

line2Appelezset() Créer un nouveau Entry,Le code sourceEntryDans l'objetk Est une référence faible pointant vers cet objet . 

4.4.1、 Pourquoi le code source est - il faiblement référencé ?

Quand function01 Une fois la méthode terminée, Stack frame destroy strong references tl Il n'y en a plus..Mais à ce stade, ThreadLocalMap Il y en a un. entry De key La référence pointe également vers cet objet    

Si ça key La référence est Forte citation ,Peut conduire à key Pointé ThreadLocal Objet et v L'objet pointé ne peut pas être gc Recyclage,Cause des fuites de mémoire;   

Si ça key La référence est Faible référence Juste Grande probabilité  Réduit les problèmes de fuite de mémoire ( Il y en a un autre. key Pour null Ray. ) .Utiliser des références faibles,Pour faire ThreadLocal L'objet a été récupéré avec succès après l'exécution de la méthode et Entry De key Les références pointent vers null . 

-- La phrase suivante, On en reparlera plus tard , Cette section est omise en premier  

Après ça, on appelle  get,set Ou remove La méthode, Je vais essayer de supprimer  key Pour null De entry ,Peut être libéré value Mémoire utilisée par l'objet.   

4.4.2、 Est - ce qu'une faible citation va tout arranger ?

Mines enfouies

1、 Quand nous sommes threadLocal Affectation des variables, En fait, c'est le moment Entry(threadLocal Exemple: key ,La valeur est: value) Par là threadLocalMap Stockage intermédiaire. Entry Dans key C'est une faible référence,Quand threadLocal Les références externes fortes sont définies à null(tl=null), Alors le système GC Quand,Selon l'analyse d'accessibilité,C'est threadLocal L'Instance n'a pas de lien auquel se référer ,C'est ThreadLocal Il doit être recyclé,C'est comme ça. , ThreadLocalMap Et ça apparaîtra key Pour null De Entry ,Il n'y a aucun moyen d'y accéder key Pour null De Entry De value ,Si le thread actuel se termine plus tard,Ces key Pour null De Entry De value Il y aura toujours une chaîne de référence forte: Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value Jamais recyclable,Cause des fuites de mémoire. 

  

2、 Quand Mais,Si actuellement thread Fin de l'opération, threadLocal , threadLocalMap,Entry Pas de chaîne de référence accessible , Les déchets sont recyclés par le système pendant le recyclage .   

   

3、 Mais en pratique Nous utilisons parfois des pools de Threads   Pour maintenir nos fils ,Comme dans Executors.newFixedThreadPool() Quand un thread est créé , Pour réutiliser les fils, ça ne se termine pas ,Alors... threadLocal Les fuites de mémoire méritent notre attention    

keyPournullDeentry,Analyse des principes

ThreadLocalMap Utiliser ThreadLocal Une faible référence à key ,Si un ThreadLocal Il n'y a pas de références externes ,Alors le système gc Quand,C'est ThreadLocal Il doit être recyclé,C'est comme ça., ThreadLocalMap Et ça apparaîtra key Pour null De Entry ,Il n'y a aucun moyen d'y accéder key Pour null De Entry De value ,Si le thread actuel se termine plus tard ( Par exemple, juste avec le pool de Threads ) ,Ces key Pour null De Entry De value Il y aura toujours une chaîne de référence forte.   

  

Même si les références sont faibles ,Promis. key Pointé ThreadLocal Les objets peuvent être recyclés à temps ,Mais v Pointé value L'objet est de ThreadLocalMap Appelez get 、 set J'ai trouvé key Pour null Pour récupérer tout entry 、 value , Les références faibles ne peuvent donc pas 100% Assurez - vous que la mémoire ne fuit pas . On va utiliser un  ThreadLocal Après l'objet,Appel manuel remove  Comment le supprimer  , Surtout dans le pool de programmes en ligne , Ce n'est pas juste une fuite de mémoire , Parce que les Threads dans le pool de Threads sont réutilisés , Ça veut dire que ce thread ThreadLocalMap Les objets sont également réutilisés , Si on n'appelle pas manuellement remove Méthodes, Il est donc possible que les fils suivants obtiennent ce que le fil précédent a laissé value Valeur,Cause bug .   

set、get La méthode vérifie que toutes les clés sont nullDeEntryObjet

set()

get()

remove()

Conclusions

De l'avantset,getEntry,removeLa méthode,InthreadLocalDans le cycle de vie,PourthreadLocal Problème de fuite de mémoire , 

Tout ira bien.expungeStaleEntry,cleanSomeSlots,replaceStaleEntry Ces trois façons de nettoyer keyPournull Sale. entry. 

4.4.3、Conclusions

4.5、Meilleures pratiques

Comment définir

N'oubliez pas de le faire manuellement remove

5、Petit résumé

ThreadLocal Ne résout pas le problème du partage des données entre les fils

ThreadLocal Pour les scénarios où les variables sont isolées entre les Threads et partagées entre les méthodes

ThreadLocal Les problèmes de sécurité des Threads d'instance sont évités en créant implicitement des répliques d'instance indépendantes dans différents Threads

Chaque thread possède une propriété exclusive MapEt l'entretienThreadLocalCartographie des objets et des instances spécifiques,LeMap Parce qu'il n'est accessible que par le thread qui le tient , Il n'y a donc pas de problème de sécurité du fil et de verrouillage

ThreadLocalMapDeEntryC'est exact.ThreadLocal La référence à est faible ,J'ai évité.ThreadLocal Problème avec les objets qui ne peuvent pas être recyclés

Tout ira bien.expungeStaleEntry,cleanSomeSlots,replaceStaleEntry Les trois méthodes de récupération des clés sont null De Entry Valeur de l'objet( C'est un exemple concret )Et Entry L'objet lui - même empêche les fuites de mémoire , Méthode de renforcement de la sécurité

Les hommes se disputent , Tout le monde est en sécurité.

原网站

版权声明
本文为[Shi xiaozan]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206111207398918.html