关于 ThreadLocal 内存泄露

在使用 ThreadLocal 的时候,一般我们的代码都是这样写的:

public class ThreadLocalDemo {
    private static final ThreadLocal<Map<String, Object>> context = ThreadLocal.withInitial(HashMap::new); 
    
    public static void setUserId(Long userId) {
        context.get().put("userId", userId);
    }
    
    public static Long getUserId() {
        return (Long) context.get().get("userId");
    }
    
    public static void remove() {
        context.remove();
    }
}

然后处理业务的是一个线程池,有一个结果就是 「ThreadLocal 引用」 context(静态变量) 和 「Thread 引用」(线程池里的线程)会常驻内存。引用关系如图所示:
在这里插入图片描述
虽然 key 使用了弱引用,但是 key 指向的 「ThreadLocal 对象」还一直被「ThreadLocal 引用」给引用着,这样 ThreadLocal 里的 expungeStaleEntry 方法是无法进行清理的(清理 key 为 null 的元素)。

ThreadLocal 的使用场景不应该图省事,就用来传递业务参数,这样增加了程序复杂度,代码可读性降低,处理不当还会内存泄漏,适用于一些日志、监控类的场景。

推荐的做法:

   try {
      ThreadLocalDemo.setUserId(124132523);
       // 业务逻辑
   } finally {
       // 当前线程处理完数据以后清理掉 ThreadLocal 里面的数据,
       // 处理业务的线程一般都是线程池,同一个线程可以处理多个请求,ThreadLocal 的数据是和请求相关的,及时清掉 ThreadLocal 里的数据,避免请求之间数据污染
       ThreadLocalDemo.remove();
   }

WeakReference:
软引用、弱引用、虚引用-他们的特点及应用场景
更多参考:
对ThreadLocal实现原理的一点思考

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值