ThreadLocal
创始人
2024-02-18 18:26:37
0

文章目录

  • 一、ThreadLocal是什么
  • 二、ThreadLocal作用
  • 三、ThreadLocal的设计结构
    • 早期:
    • 现在:
  • 四、ThreadLocal核心方法
    • 1. set方法
    • 2. get方法
    • 3. remove方法
  • 五、ThreadLocal内存泄漏
  • 六、使用场景
  • 七、参考资料


前言:
再写博客时,遇到了如何处理保存用户的信息时出现混乱的问题(线程安全问题),在一番查找后,寻到了ThreadLocal用来保存登录的用户的信息的方法。


一、ThreadLocal是什么

在讲ThreadLocal前,先来看一下什么是线程封闭

封闭对应的是开放,所谓线程开放就是类似共享数据、共享变量这些概念。
多线程访问共享可变数据时,涉及到线程间数据同步问题。并不是所有时候,都要用到共享数据,所以线程封闭的概念就提出来了。

当访问共享的可变数据时,通常需要使用同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程内访问数据,就不需要同步。这种技术被称为线程封闭。它是实现线程安全最简单的方式之一。当某个对象封闭在一个线程中时,这种用法将自动实现线程安全性。即使被封闭的对象本身不是线程安全的。

那么,要如何维持线程封闭呢,这时我们就可以使用ThreadLocal来使线程中的某个值与保存值的对象关联起来。

ThreadLocal说简单点就是往一个线程存数据,这个数据只能由这个线程获取,其他线程无法获取这个数据
ThreadLocal就是用空间换时间,Synchronized就是时间换空间

在这里插入图片描述
此图对于理解ThreadLocal十分重要


二、ThreadLocal作用

public class th {private String content;private String getContent() {return content;}private void setContent(String content) {this.content = content;}public static void main(String[] args) {th demo = new th();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}
}

在这里插入图片描述
在实际运行后,便出现了如上的结果,线程之间不隔离,每个线程获取的数据出现了错误,使用ThreadLocal,便可以很好的解决此问题。

ThreadLocal作用便是提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。

  1. 线程并发: 在多线程并发的场景下
  2. 传递数据: 我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量
  3. 线程隔离: 每个线程的变量都是独立的,不会互相影响

三、ThreadLocal的设计结构

早期:

在这里插入图片描述

现在:

在这里插入图片描述

每个Thread维护一个ThreadLocalMap,这个Map的keyThreadLocal实例本身,value才是真正要存储的值Object

每个Thread线程都有一个ThreadLocalMap(Map结构,但是不是直接使用的Map)
ThreadLocalMap中储存了key(ThreadLocalMap对象)和value(Object)
ThreadLocalMap由ThreadLocal维护,意思就是由ThreadLocal负责获取和设置 每一个线程互不干扰,形成隔离

好处:

  • 每个Map存储的Entry数量就会变少。因为之前的存储数量由Thread的数量决定,现在是由ThreadLocal的数量决定。在实际运用当中,往往ThreadLocal的数量要少于Thread的数量。
  • Thread销毁之后,对应的ThreadLocalMap也会随之销毁,能减少内存的使用。

四、ThreadLocal核心方法

静下心来看源码

1. set方法

    public void set(T value) {Thread t = Thread.currentThread();  //获取当前线程对象ThreadLocalMap map = getMap(t);  //获取此线程对象中维护的ThreadLocalMap对象if (map != null) {map.set(this, value);} else {createMap(t, value);}}ThreadLocalMap getMap(Thread t) {return t.threadLocals;}void createMap(Thread t, T firstValue) {//  this是调用此方法的threadLocalt.threadLocals = new ThreadLocalMap(this, firstValue);}

2. get方法

    public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {// 以当前的ThreadLocal 为 key,调用getEntry获取对应的存储实体eThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;   // 取值return result;}}return setInitialValue();   // 设置初始化值}   private T setInitialValue() {T value = initialValue(); // 获取初始化值 初为null,可重写Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t); // 获取此线程对象中维护的ThreadLocalMap对象if (map != null) {map.set(this, value);} else {createMap(t, value);}if (this instanceof TerminatingThreadLocal) {TerminatingThreadLocal.register((TerminatingThreadLocal) this);}return value;}private Entry getEntry(ThreadLocal key) {int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];if (e != null && e.get() == key)return e;elsereturn getEntryAfterMiss(key, i, e);}protected T initialValue() {return null;}

3. remove方法

     public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null) {m.remove(this);}}

五、ThreadLocal内存泄漏

强引用:只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了.

软引用:在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。

弱引用:无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。

虚引用:如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收。

内存泄漏:指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

在这里插入图片描述
一个线程属于强引用,对于一整个生命周期
当key为强引用时,key和value会一直存在,Entry不会被回收,从而导致内存泄漏
当key为弱引用时,在线程的生命周期中进行了一次垃圾回收,此时key作为弱引用被干掉了,但是整个线程还是存在,此时在Map中只有value,便会永远存在于内存中,当有大量的此行为时,便可能会造成内存泄漏

我们得知两个引用都有风险,但是为什么选择了弱引用呢?
我们是通过ThreadLocal来对ThreadLocalMap进行操作的,假设使用ThreadLocal的对象被设置为null了,那ThreadLocalMap的强引用指向ThreadLocal也毫无意义。弱引用反而可以预防大多数内存泄漏的情况,毕竟被回收后,下一次调用set/get/remove时ThreadLocal内部会清除掉


六、使用场景

1.用于保存线程不安全的工具类,如SimpleDateFormat
2.每个线程需要独立保存信息,如个人博客中保存的用户信息


七、参考资料

https://www.zhihu.com/question/399087116/answer/2763547159
https://www.bilibili.com/video/BV1QS4y1s7hi
https://blog.csdn.net/LemonSnm/article/details/122251312
https://www.cnblogs.com/liyutian/p/9690974.html

相关内容

热门资讯

小学学校消防演练总结 小学学校消防演练总结(精选8篇)  总结是指对某一阶段的工作、学习或思想中的经验或情况加以总结和概括...
预防接种工作总结通用25篇 预防接种工作总结 第一篇20xx年预防接种查验工作,在镇教委的协调和支持下,在县疾控中心的指导下,通...
幼儿园小班第二学期个人教学工... 幼儿园小班第二学期个人教学工作总结  总结是事后对某一阶段的学习或工作情况作加以回顾检查并分析评价的...
年终工作总结物业推荐37篇 年终工作总结物业 第一篇一年的时间转眼就过去了,我们___物业在20__年的工作也暂时告一段落。在这...
工程项目经理年终工作总结 工程项目经理年终工作总结工程项目经理年终工作总结2009-07-30 11:25 P.M.一、认真贯...
高中教师个人总结与自我评价   作为教师,在年底了有必要为自己这一年的工作一个总结,也得给自己的综合的评价。下面CN人才网小编为...
村级代办员工作总结推荐7篇 村级代办员工作总结 第一篇为切实加强农村档案管理,全面提升我村档案管理水平,更好的为社会主义新农村建...
土木工程概论总结 土木工程概论总结(精选8篇)  总结是把一定阶段内的有关情况分析研究,做出有指导性的经验方法以及结论...
小学教师考核个人总结 小学教师考核个人总结  总结是事后对某一阶段的学习或工作情况作加以回顾检查并分析评价的书面材料,它可...
政法委工作总结通用13篇 政法委工作总结 第一篇今年以来,师市党委政法委以科学发展观为指引,深入贯彻党的十八大、十八届六中全会...
小学班主任年终工作总结 关于小学班主任年终工作总结范文汇总8篇  总结就是把一个时段的学习、工作或其完成情况进行一次全面系统...
医院试用期转正个人工作总结 医院试用期转正个人工作总结医院试用期转正个人工作总结一文是介绍医院试用期转正相关的个人工作总结范文,...
实习期个人工作总结推荐76篇 实习期个人工作总结 第一篇通过这次实习,让我们去更多的了解一些设备,还有钢铁生产的主要流程等,最主要...
幼儿园保健医生工作总结 幼儿园保健医生工作总结(通用11篇)  时间一晃而过,一段时间的工作活动告一段落了,经过过去这段时间...
如何添加打印机 有网友想将自己的电脑连接到局域网打印机上,但是不知道“如何连接局域网打印机?”,所以聘才小编总结了连...
员工转正工作总结 精选员工转正工作总结四篇  总结是把一定阶段内的有关情况分析研究,做出有指导性的经验方法以及结论的书...
工作总结分析推荐19篇 工作总结分析 第一篇时光如梭,转眼即将告别20XX年,回顾过去的一年工作,内心不禁感慨万千,虽然工作...
银行柜员个人年度工作总结 银行柜员个人年度工作总结(精选18篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其...
酒店销售工作总结 关于酒店销售工作总结范文9篇  总结是在一段时间内对学习和工作生活等表现加以总结和概括的一种书面材料...
初中班主任工作总结 初中班主任工作总结(大全)  总结是指对某一阶段的工作、学习或思想中的经验或情况加以总结和概括的书面...