ThreadLocal 原理及源码分析(含内存泄漏)

ThreadLocal 原理及源码分析

强引用:普通引用
软引用:一般用于缓存
弱引用:一般用于Map集合的清理,如ThreadLocalMap清理
虚引用:JVM中用于管理直接内存


一、ThreadLocal 是什么?

ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

场景:
(1)ThreadLocal 的经典使用场景是数据库连接和 session 管理等。
(2)Spring的Transaction的实现、MyBatis的分页实现等等。


二、测试类

因为ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以导致如下代码中,线程2在从ThreadLocal 中get()时获取不到线程1存入的值,导致抛出异常。

package com.company.test;

import com.company.entity.User;

/**
 * @author zhangxh
 * @Description:
 * @date 2020-08-14
 */
public class ThreadLocalTest {

    static ThreadLocal tl = new ThreadLocal();

    public static void main(String[] args) {
        new Thread(()->{
            tl.set(new User(1, "张三", 23));

            User user = (User) tl.get();
            System.out.println(user.getName()); // 张三
        },"线程1").start();

        new Thread(()->{
            User user = (User) tl.get();
            System.out.println(user.getName());
            //Exception in thread "线程2" java.lang.NullPointerException
        },"线程2").start();

    }

}

二、源码原理分析

2.1 ThreadLocal 的set方法原理

首先,我们使用 ThreadLocal tl = new ThreadLocal(); 创建了一个ThreadLocal对象,然后在 tl.set(new User(1, "张三", 23)); 的时候,将tl变量(即所指向对象的hash值)作为key、set方法的参数new User()作为value设置到ThreadLocal中的ThreadLocalMap中(这里ThreadLocalMap为每个线程对象Thread的独有的全局变量ThreadLocals,这样就把对象与每个线程“绑定起来”,即作为线程的变量副本,线程间互不影响)。

在这里插入图片描述


2.2 ThreadLocal内存泄漏问题(为什么Entry要使用弱引用?)

假设 Entry使用强引用,如下图,当我们不想使用ThreadLocal时,此时将 tl 强引用置为null时,由于ThreadLocalMap中存在强引用指向ThreadLocal对象,故gc仍然无法回收ThreadLocal对象,造成对象无法回收问题(造成内存泄漏)。

在这里插入图片描述


若Entry使用弱引用(如下图),当我们不想使用ThreadLocal时,设置 tl=null,此时由于key的引用指向ThreadLocal对象为弱引用(特点:只要经历gc即被回收),所以弱引用可以解决此处的内存泄漏问题。

在这里插入图片描述

但当经历gc之后,ThreadLocal被回收,对应的key值变成null,此处会导致该key为null的Entry数据对应的value所占内存再也无法被访问到(即无法被回收),造成内存泄露问题。

解决方法:

注:
(1)尽管ThreadLocal在set和get时,会自行清理key为null的Entry对象,但不能时刻保证key为null的Entry被及时清理,故
建议当我们不想使用ThreadLocal时,需要手动执行 tl.remove();以释放对应内存。
(2)如果threadLocals位于线程池中,每次使用完务必清理本地的threadLocals,防止其他线程从线程池中拿到该对象后,里面的旧数据影响其他线程。


2.3 ThreadLocalMap中的Hash算法与处理Hash一致性问题(线性探测)

ThreadLocalMap与HashMap相似,但解决冲突方法不一样,HashMap采用的是拉链法,ThreadLocalMap采用线性探测法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值