首页 > 其他分享 >ThreadLocal使用

ThreadLocal使用

时间:2024-02-16 15:12:48浏览次数:28  
标签:Thread ThreadLocalMap value ThreadLocal 线程 使用 null

 Thread:

Thread类中有两个变量threadLocals和inheritableThreadLocals,两者都是ThreadLocal.ThreadLocalMap类型,默认情况下为null,对应源码为

1     ThreadLocal.ThreadLocalMap threadLocals = null;
2 
3     ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;ritableThreadLocals = null;

ThreadLocalMap:

ThreadLocalMap是ThreadLocal类的一个内部类,它的数据结构类似HashMap,key为当前的ThreadLocal对象(key的初始化是通过super(k)实现,也就是通过其父类WeakReference的构造函数实现,所以这里的key的引用类型为弱引用),value为Object类型,源码如下:

1         static class Entry extends WeakReference<ThreadLocal<?>> {
2             /** The value associated with this ThreadLocal. */
3             Object value;
4 
5             Entry(ThreadLocal<?> k, Object v) {
6                 super(k);
7                 value = v;
8             }
9         }

 ThreadLocal.set():

当线程调用ThreadLocal的set方法时,会根据获取当前Thread的threadLocals值,如果为null则初始化,如果不为null则将当前传入value塞入ThreadLocal中,源码如下:

1     public void set(T value) {
2         Thread t = Thread.currentThread();
3         ThreadLocalMap map = getMap(t);
4         if (map != null)
5             map.set(this, value);
6         else
7             createMap(t, value);
8     }

初始化过程为将当前ThreadLocal当做key,传入的值当做value赋值给当前Thread的threadlocals变量,源码如下:

1     void createMap(Thread t, T firstValue) {
2         t.threadLocals = new ThreadLocalMap(this, firstValue);
3     }

注意:当前线程的本地变量是放在线程的threadLocals变量里的(也就是Thread的变量里),而ThreadLocal本身类似一个工具壳,通过set将value添加到Thread的threadlocals的变量中。

ThreadLocal.get():

get方法会去获取当前线程的threadlocals变量,如果不为null,则直接返回ThreadLocalMap的value,如果为空,则初始化,源码如下:

 1  public T get() {
 2         Thread t = Thread.currentThread();
 3         ThreadLocalMap map = getMap(t);
 4         if (map != null) {
 5             ThreadLocalMap.Entry e = map.getEntry(this);
 6             if (e != null) {
 7                 @SuppressWarnings("unchecked")
 8                 T result = (T)e.value;
 9                 return result;
10             }
11         }
12         return setInitialValue();
13     }

其中threadlocals不为null,直接通过当前的TreadLocal值当做key去获取value。

如果threadlocals为null,则调用初始化方法,过程与set方法类似,只不过value赋值为null,源码如下:

 1   private T setInitialValue() {
 2         T value = initialValue();
 3         Thread t = Thread.currentThread();
 4         ThreadLocalMap map = getMap(t);
 5         if (map != null)
 6             map.set(this, value);
 7         else
 8             createMap(t, value);
 9         return value;
10     }

ThreadLocal.remove():

移除当前线程的ThreadLocal对象,包括ThreadLocalMap的key和value。

在上述set方法和treadlocal初始化的时候,entry对象的key的引用类型被传递给了WeakReference的构造函数,也就是key的引用类型为弱引用。

如果不调用ThreadLocal的remove方法释放对象的话,那么gc会回收当前ThreadLocalMap的ThreadLocal对象,则会出现ThreadLocalMap的key为null,但是value不为null的entry对象,则会造成内存泄漏。

threadlocals变量和inheritableThreadLocals的区别:

同一个ThreadLocal变量在父线程中被设置值后,在子线程中是获取不到的(threadLocals中为当前调用线程对应的本地变量,所以二者自然是不能共享的),InheritableThreadLocal可以实现共享。

InheritableThreadLocal实现父子线程变量共享的原因:

查看Thread类源码可以发现,在当前Thread进行init方法初始化的时候,会去调用currentThread获取父线程,我的理解是这个时候子线程还未创建完成,这个时候获取的currentThread仍是父线程,然后通过获取到的parent Thread获取父线程中的InheritableThreadLocal,将parent Thread中的InheritableThreadLocal赋值给当前线程的InheritableThreadLocal,由此完成父子线程间变量的共享,这个共享的实现其实也是获取变量然后重新复制一份给子线程实现的

标签:Thread,ThreadLocalMap,value,ThreadLocal,线程,使用,null
From: https://www.cnblogs.com/zeevy/p/18017171

相关文章

  • JSON相关注解的使用
    1.@JsonInclude当使用json进行序列化时,往往会遇到某个实体对象的属性为null,可以使用如下类注解使得属性值为null的时候Java Bean不参与序列化可以作用在类上,也可以作用在字段上@JsonInclude(JsonInclude.Include.NON_NULL)     其他常量值包括:Include.Include.ALWAYS   ......
  • StringUtils使用与源码分析
    在apache的lang3包中有个StringUtils工具类,该工具类为开发中常用的字符串处理工具类 非空判断,isBlank和isEmpty这俩方法的形参都是charSequence字符序列。isEmpty判断这个字符序列是否为null,还有长度是否为0,如果是,则返回true,反之返回falseisBlank在isEmpty之上还有一个,如果长度......
  • 《程序是怎样跑起来的》第四章——熟练使用有棱有角的内存?
    关于这一章,是目前让我最感兴趣的一章,因为说到了内存,在编程过程中我经常遇到内存这类的问题,如堆、栈溢出,如何更好的使用内存,所以对内存格外想要了解。内存的实体实际上是一种名为内存IC的电子元件,有多种类型如:RAM,ROM等等。内存IC中有电源、控制信号、地址信号、数据信号。通过地址......
  • VS Code 使用 php cs fixer 扩展根据 psr 规范修复/格式化代码
    参考https://github.com/PHP-CS-Fixer/PHP-CS-Fixerhttps://www.cnblogs.com/huangtailang/p/6604124.html环境软件/系统版本说明WindowsWindows10专业版22H219045.4046phpphp-8.2.5-nts-Win32-vs16-x64vscode1.86.2phpcsfixerv0.3.11vs......
  • MyBatis-Plus--在xml中使用wrapper的方法
    原文网址:​​MyBatis-Plus--在xml中使用wrapper的方法_IT利刃出鞘的博客-CSDN博客​​简介本文介绍MyBatis-Plus如何在xml中使用wrapper。分享Java技术星球(自学精灵):​​https://learn.skyofit.com​​ServiceQueryWrapper<T>wrapper=newQueryWrapper<T>();wrapper.eq("......
  • 机器视觉-tensorBoard使用说明
    tensorboard功能Yolov8源码已经集成了很多个metrics监控系统,源码位置:ultralytics\utils\callbacks\,包括wandb、tensorboard、clearml等等.和其他系统相比,tensorboard功能较弱.yolov8自动集成tensorboard功能包括:查看学习率查看mAP/precision/recall指标......
  • 8小时速成golang(五)golang高阶 channel基本定义和使用
     1、定义channel变量channel是Go语言中的一个核心类型,可以把它看成管道。并发核心单元通过它就可以发送或者接收数据进行通讯,这在一定程度上又进一步降低了编程的难度。 channel是一个数据类型,主要用来解决go程的同步问题以及go程之间数据共享(数据传递)的问题。goroutin......
  • Nginx系列--rewrite的使用
    原文网址:​​Nginx系列--rewrite的使用_IT利刃出鞘的博客-CSDN博客​​简介本文介绍Nginx中rewrite的使用。分享Java技术星球(自学精灵):​​learn.skyofit.com​​语法rewriteregexURL[flag];flag标志位last:停止处理rewrite,并对配更改后的URI重新进行搜索(再从server......
  • Django使用聚合查询(价格乘以总数得到总价,并以总价排名)
    自定义库存表(Stock)classStock(models.Model):amount=amount=models.IntegerField(verbose_name='数量')price=models.DecimalField(max_digits=10,decimal_places=2,verbose_name='单价')使用模板语法完成自定义查询:Stock.objects.annotate(profit=F(......
  • 如何使用TailwindCSS和JavaScript构建自定义的HTML5视频播放器
    HTML5自带了一个原生视频播放器。它在浏览器中配备了简单的用户界面、功能和一些基本的控件。尽管通过浏览器的默认视频播放器的功能完美运行,但用户界面并不那么美观和时尚,总体上并不令人满意。因此,大多数现代Web应用程序和平台,如Udemy、Netflix、YouTube和AmazonPrime,不会将默......