ThreadLocal使用场景及内存泄漏

定义

ThreadLocal官方定义: 该类提供线程局部变量。这些线程局部变量与普通变量的不同,每个线程都有自己独立初始化的变量副本(通过其get或set方法)。
如果希望将类的局部变量和线程状态关联(如 user id 或者 transcation id ), 就可以使用ThreadLocal.

如何使用它们

ThreadLocal的简单示例

private static ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> "default");
public static void main(String[] args) throws InterruptedException {
        threadLocal.set("in main class");
        System.out.println("1 " + threadLocal.get());
        ExecutorService service = Executors.newFixedThreadPool(1);
        service.submit(() -> {
            System.out.println("2 " + threadLocal.get());
            threadLocal.set("in sub thread");
            System.out.println("3 " + threadLocal.get());
        });
        service.shutdown();
        Thread.sleep(500);
        System.out.println("4 " + threadLocal.get());
    }
//输出: 1 in main class
//2 null
//3 in sub thread
//4 in main class

从上面的示例可以看出, 在不同的线程中对ThreadLocal变量进行set和get操作时, 它们的变量是相互独立的.

为什么ThreadLocal能实现线程变量隔离

从源码中可知, 每一个Thread内部都有一个ThreadLocalMap, ThreadLocalMap里面 Key是当前ThreadLocal对象, Value是线程对应的变量副本, ThreadLocal所做的事情就是 负责维护每个Thread内部的ThreadLocalMap.
ThreadLocal的核心方法

T get();   // 获取本地线程变量
void set(T value) // 设置本地线程变量
void remove(); // 移除本地线程变量

get()的执行内容:
1. 根据Thread.currentThread() 获取当前执行线程信息, 并根据当前线程对象获取该线程的ThreadLocalMap对象
2. 若map不为空, 直接根据当前ThreadLocal对象获取entry, 进入过去value副本并返回
3. 若map为空, 将线程变量副本写入null, 并返回null.

set()的执行内容:
1. 根据Thread.currentThread() 获取当前执行线程信息, 并根据当前线程对象获取该线程的ThreadLocalMap对象
2. 若map不为空, 将ThreadLocal对象和值写入到当前线程对应的map中.
3. 若map为空, 则需要初始化当前线程的ThreadLocalMap对象, 再写入ThreadLocal和value的副本.

remove()的执行内容:
1. 获取当前线程的ThreadLocalMap并移除Key为当前ThreadLocal对象的键值对.

ThreadLocal的问题(可能内存泄漏)

当ThreadLocal存储了很多 Key = null 的Entry时, 但长时间不结束当前thread 且不再调用get(), set(), remove() 方法, 那么当ThreadLocal对象被回收后, Key是弱引用也被回收, 但是Value是强引用, 一直不回收, 就容易导致内存泄漏.
如何解决该问题: 每次调用完ThreadLocal之后, 都调用remove()方法, 手动销毁数据.

ThreadLocal带来的好处

  1. ThreadLocal把操作的数据存储在了线程本地, 直接本地内存读取, 不再需要synchronized等同步的方式修改主内存的数据, 然后再复制到本地内存, 提高了访问效率. 这也是为什么ThreadLocal能解决线程安全的问题.
    ThreadLocal和线程同步的一些异同: 同步机制采用了“以时间换空间”的方式: 串行访问数据, 并共享对象. 而ThreadLocal采用了“以空间换时间”的方式: 并行访问,独享对象.

主要应用场景

  1. 在维护每个线程的Session的时候, ThreadLocal能帮助我们在每个线程中独享资源.
  2. 数据库连接在多线程读取的时候, 使用ThreadLocal包装, 能将线程和数据库连接绑定, 方便事务操作.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值