当前位置:网站首页>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: 51.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é.
边栏推荐
- C reads TXT file to generate word document
- Zabbix安装及配置应用
- Acwing50+Acwing51周赛+Acwing3493.最大的和(未完结)
- YARN 切换ResourceManager(Failed to connect to server:8032 retries get failed due to exceeded maximum)
- Linux changes the MySQL password after forgetting it
- When a pure data service machine calls in, it falls back to 2g/3g
- 反射真的很耗时吗,反射 10 万次,耗时多久。
- 带你了解直接插入排序(C语言)
- 纯数据业务的机器打电话进来时回落到了2G/3G
- flink 部署模式和运行时架构(会话模式、单作业模式、应用模式,JobManager、TaskManager,YARN 模式部署以及运行时架构)
猜你喜欢

flink Window Join、Interval Join、Window CoGroup (两流匹配 指定key联结,开窗口进行窗口操作)

深度学习与CV教程(14) | 图像分割 (FCN,SegNet,U-Net,PSPNet,DeepLab,RefineNet)

Flink physical partition (random partition, polling partition, rescaling partition, broadcast, global partition, custom partition)

Flip window join, interval join, window cogroup

Elk - x-pack set user password

9、聊聊ThreadLocal

C# 将OFD转为PDF

Acwing50+acwing51 weeks +acwing3493 Maximum sum (open)

Guangdong municipal safety construction data management software 2022 new forms are coming

微信web开发者,如何学习web开发
随机推荐
Using fast and slow pointer method to solve the problem of array (C language)
采用快慢指针法来解决有关数组的问题(C语言)
Is the SSL certificate reliable in ensuring the information security of the website?
Splunk健康检查orphaned searches
POJ 3278 catch the cow (width first search, queue implementation)
Splunk 最佳实践-减轻captain 负担
Wechat authorization to obtain mobile phone number
Addition of large numbers (C language)
ftp服務器:serv-u 的下載及使用
Software project management 7.1 Basic concept of project schedule
flink 时间语义、水位线(Watermark)、生成水位线、水位线的传递
Solve the problem of swagger document interface 404
Record a troubleshooting of MySQL master-slave asynchrony
InputStream读取文件OutputStream创建文件
C reads TXT file to generate word document
Flip window join, interval join, window cogroup
Notes on topic brushing (XIV) -- binary tree: sequence traversal and DFS, BFS
Specflow环境搭建
flink 物理分区( 随机分区、 轮询分区、重缩放分区、 广播、 全局分区、自定义分区 )
ftp服务器:serv-u 的下载及使用