ThreadLocal详解

本文介绍了ThreadLocal在Spring事务隔离中的应用,解决日期解析冲突的案例,以及如何避免ThreadLocal引起的内存泄露。重点讨论了ThreadLocal的工作原理、内存管理与解决方案。
摘要由CSDN通过智能技术生成

基本概念

ThreadLocal的基本作用就是数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是隔离的。

隔离用在哪里?

spring实现事务隔离的底层就使用了ThreadLocal。

保证单个线程中的数据库操作使用的是同一个数据库连接。同时采用这种返回格式可以使业务层使用事务不需要感知并且管理connection对象,通过传播级别,穷啊秒的管理多个事务配置之间的切换 挂起 和 恢复。

Spring框架里面就是用的ThreadLocal来实现这种隔离,主要是在TransactionSynchronizationManager这个类里面

你使用过这个吗?(加分项)

之前我们上线后发现部分用户的日期居然不对了,排查下来是SimpleDataFormat的锅,当时我们使用SimpleDataFormat的parse()方法,内部有一个Calendar对象,调用SimpleDataFormat的parse()方法会先调用Calendar.clear(),然后调用Calendar.add(),如果一个线程先调用了add()然后另一个线程又调用了clear(),这时候parse()方法解析的时间就不对了。

其实要解决这个问题很简单,让每个线程都new 一个自己的 SimpleDataFormat就好了,但是1000个线程难道new1000个SimpleDataFormat

所以当时我们使用了线程池加上ThreadLocal包装SimpleDataFormat,再调用initialValue让每个线程有一个SimpleDataFormat的副本,从而解决了线程安全的问题,也提高了性能。

ThreadLocal的底层

ThreadLocal<String> localName = new ThreadLocal();
localName.set("张三");
String name = localName.get();
localName.remove();

set源码

public void set(T value) {
    Thread t = Thread.currentThread();// 获取当前线程
    ThreadLocalMap map = getMap(t);// 获取ThreadLocalMap对象
    if (map != null) // 校验对象是否为空
        map.set(this, value); // 不为空set
    else
        createMap(t, value); // 为空创建一个map对象
}

大家可以发现set的源码很简单,主要就是ThreadLocalMap我们需要关注一下,而ThreadLocalMap呢是当前线程Thread一个叫threadLocals的变量中获取的。

每个线程Thread都维护了自己的threadLocals变量,所以在每个线程创建ThreadLocal的时候,实际上数据是存在自己线程Thread的threadLocals变量里面的,别人没办法拿到,从而实现了隔离。

ThreadLocalMap底层结构

数组 不是hashmap

用数组是因为,我们开发过程中可以一个线程可以有多个TreadLocal来存放不同类型的对象的,但是他们都将放到你当前线程的ThreadLocalMap里,所以肯定要数组来存。

ThreadLocal的内存泄露问题

ThreadLocal在保存的时候会把自己当做Key存在ThreadLocalMap中,正常情况应该是key和value都应该被外界强引用才对,但是现在key被设计成WeakReference弱引用了。

img

这就导致了一个问题,ThreadLocal在没有外部强引用时,发生GC时会被回收,如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。

就比如线程池里面的线程,线程都是复用的,那么之前的线程实例处理完之后,出于复用的目的线程依然存活,所以,ThreadLocal设定的value值被持有,导致内存泄露。

按照道理一个线程使用完,ThreadLocalMap是应该要被清空的,但是现在线程被复用了。

解决方案

在代码的最后使用remove就好了,我们只要记得在使用的最后用remove把值清空就好了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值