gball个人知识库
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)

ggball

后端界的小学生
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)
  • 面试

  • 数据库

  • linux

  • node

  • tensorFlow

  • 基础组件

  • 基础知识

    • java集合

    • jvm调优

    • java并发编程

      • 进程与线程
      • 多线程的方法介绍与使用
      • 线程死锁
      • 守护线程与用户线程
      • ThreadLocal了解
        • 原理解析
      • 什么是多线程并发编程
      • unsafe类了解
      • 伪共享
      • 锁的了解
      • ThreadLocalRandom原理解析
      • LongAdder,LongAccumulator类了解
      • 实践-创建多少线程合适
      • 线程通信——通知与等待
      • 缓存一致性问题
      • 利用Excutors异步执行任务
      • 线程池
      • 线程池操作数据库造成死锁
      • Java 浅拷贝和深拷贝的理解和实现方式
      • java内存模型JMM
      • 锁升级过程
      • io模型
      • 关键字介绍
      • AQS解析
    • java网络编程

    • java8新特性

    • javaAgent

    • java高级

  • 算法与设计模式

  • 分布式

  • 疑难杂症

  • go学习之旅

  • 极客时间

  • 知识库
  • 基础知识
  • java并发编程
ggball
2022-04-26

ThreadLocal了解

# ThreadLocal了解

# 原理解析

20220426201457

通过ThreadLocal获取当前线程保存的值的流程:

  1. 先得到当前线程对象
  2. 再从当前线程获取ThreadLocalMap
  3. 最后传入this(即ThreadLocal)获取对应的值

创建ThreadLocal时,里面的属性并未初始化,只有当第一次set时才会创建容器,且装数据的容器也不是放在ThreadLocal里面的,而是在Thread里面,一个是threadLocals,一个是inheritableThreadLocals,(数据结构都是hashMap)ThreaLocal只负责操作数据,并不负责储存

image-20220426201313988

threadLocals:使用ThreadLocal操作(get,set)数据时,数据都是保存在线程的threadLocals中。 inheritableThreadLocals:使用InheritableThreadLocal类操作数据时,数据会保存在inheritableThreadLocals中。

那既然有一个容器threadLocals了,那为什么还要一个inheritableThreadLocals呢?

因为ThreadLocal中只会保存本线程操作过的数据,如果子线程想访问父线程,只通过ThreadLocal是不行的,因为他们只属于这两个线程,对应着两个threadLocals。 所以jdk的开发者们想再在创建一个类似ThreadLocal的类-InheritableThreadLocal类 不去操作threadLocals,而是操作inheritableThreadLocals变量,父线程可以将想要传递的数据放到inheritableThreadLocals里面,然后子线程初始化的时候还会检查,父线程的inheritableThreadLocals有没有数据,如果有的话,则加入到子线程的inheritableThreadLocals中。

THreadLocal使用案例

 /**
     * threadLocal 使用
     * @throws InterruptedException
     */
    @Test
    public void useCaseThreadLocal() throws InterruptedException {

        MyThreadLocal myThreadLocal = new MyThreadLocal();

        Thread thread1 = new Thread(() -> {
            myThreadLocal.threadLocal.set("thread1 set value");
            myThreadLocal.print();
        });

        Thread thread2 = new Thread(() -> {
            myThreadLocal.threadLocal.set("thread2 set value");
            myThreadLocal.print();
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

利用InheritableThreadLocal实现父线程传递变量给子线程


    /**
     * 父线程传递变量到子线程
     * @throws InterruptedException
     */
    @Test
    public void parentTransferDataToChild() throws InterruptedException {


        ThreadLocal<String> threadLocal =  new InheritableThreadLocal<String>();
        threadLocal.set("parent' data");


        Thread thread1 = new Thread(() -> {
            System.out.println("子线程:"+threadLocal.get());
        });


        thread1.start();
        thread1.join();
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# ThreadLocal 内存泄露的原因

img

首先明白ThreadLocal和TheadLocalMap,Entry的关系

当线程结束时,因为 ThreadLocal标记为WeakReference弱引用,堆里面的ThreadLocal会被下一次GC扫描并回收掉,

但是Entry中的value存在强引用,所以可能会造成内存泄露。

当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。

解决办法:

手动释放资源

ExecutorService es;
ThreadLocal tl;
es.execute(()->{
  //ThreadLocal 增加变量
  tl.set(obj);
  try {
    // 省略业务逻辑代码
  }finally {
    // 手动清理 ThreadLocal 
    tl.remove();
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
上次更新: 2025/06/04, 15:06:15
守护线程与用户线程
什么是多线程并发编程

← 守护线程与用户线程 什么是多线程并发编程→

最近更新
01
AIIDE
03-07
02
githubActionCICD实战
03-07
03
windows安装Deep-Live-Cam教程
08-11
更多文章>
Theme by Vdoing
总访问量 次 | 总访客数 人
| Copyright © 2021-2025 ggball | 赣ICP备2021008769号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×

评论

  • 评论 ssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
×