当前位置: 首页 > article >正文

ThreadLocal使用和原理

文章目录

      • 业务场景
      • 底层的结构
      • 内存泄露

业务场景

ThreadLocal 用来创建线程的局部变量,每一个线程都拥有该变量的独立副本,互相不会干扰。

可以存储上下文的基本信息,比如 userId.

比如用户评论了某个文章,肯定要记录用户的 ID,但是用户请求过来正常是不携带 ID,可以将 ID 存储到 ThreadLocal 中去,在插入的时候就可以拿到 ID。

public class UserHolder {
    private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();

    public static void saveUser(UserDTO user){
        tl.set(user);
    }

    public static UserDTO getUser(){
        return tl.get();
    }

    public static void removeUser(){
        tl.remove();
    }
}

在登录拦截器中 获取到请求头中的 token. 将用户信息保存到 ThreadLocal 中去。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 1.获取请求头中的token
    String token = request.getHeader("authorization");
    if (StrUtil.isBlank(token)) {
        return true;
    }
    // 2.基于TOKEN获取redis中的用户
    String key  = LOGIN_USER_KEY + token;
    Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
    // 3.判断用户是否存在
    if (userMap.isEmpty()) {
        return true;
    }
    // 5.将查询到的hash数据转为UserDTO
    UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
    // 6.存在,保存用户信息到 ThreadLocal
    UserHolder.saveUser(userDTO);
    // 7.刷新token有效期
    stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);
    // 8.放行
    return true;
}

程序运行完成后需要移除 Threadlcoal 的数据,避免内存泄漏。

  @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 移除用户
        UserHolder.removeUser();
    }

底层的结构

ThreadLocal 里面有一个结构 ThreadLocalMap 用来存储数据。

每一个 Thread 对应一个 ThreadLocalMap。

map 里面是一个 Entry 数组,key 是根据 TheadLocal 计算出来的数组下标,value 就是用户存储的值进去。

static class ThreadLocalMap {

    /**
     * The entries in this hash map extend WeakReference, using
     * its main ref field as the key (which is always a
     * ThreadLocal object).  Note that null keys (i.e. entry.get()
     * == null) mean that the key is no longer referenced, so the
     * entry can be expunged from table.  Such entries are referred to
     * as "stale entries" in the code that follows.
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }

    /**
     * The initial capacity -- MUST be a power of two.
     */
    private static final int INITIAL_CAPACITY = 16;

    /**
     * The table, resized as necessary.
     * table.length MUST always be a power of two.
     */
    private Entry[] table;

    /**
     * The number of entries in the table.
     */
    private int size = 0;

    /**
     * The next size value at which to resize.
     */
    private int threshold; // Default to 0

createMap 方法

get 方法

内存泄露

内存泄露的概念:

内存泄露(Memory Leak)指的是在程序运行过程中,动态分配的内存空间没有被及时释放,导致这些内存资源一直被占用,最终可能导致系统内存耗尽。简单来说,就是程序中不再使用的内存没有被回收,但程序依然持有该内存的引用,造成内存资源的浪费。

ThreadLocal 在使用中可能会出现内存泄露的情况,

正常 Thread 线程执行任务结束后,Thread 与 map 之间的引用关系就不存在了,GC 会 自动回收掉。

但是我们在实际开发中经常会用线程池来复用线程,这两个之间的引用就会一直存在。

因为 Entry 是弱引用,继承了 WeakReference。

Key 是可以被自动回收的,但是 Value 还在被引用,Value 不能回自动回收,这种情况下就会又内存泄露的风险。


http://www.kler.cn/a/532309.html

相关文章:

  • 【数据结构篇】时间复杂度
  • Jenkins 触发构建的几种常见方式
  • deep generative model stanford lecture note3 --- latent variable
  • 首发!ZStack 智塔支持 DeepSeek V3/R1/ Janus Pro,多种国产 CPU/GPU 可私有化部署
  • 关于安卓greendao打包时报错问题修复
  • 97,【5】buuctf web [极客大挑战 2020]Greatphp
  • 【Unity2D 2022:UI】创建滚动视图
  • CTFHub信息泄露PHPINFO
  • Qt展厅播放器/多媒体播放器/中控播放器/帧同步播放器/硬解播放器/监控播放器
  • win32汇编环境,对话框程序生成选项卡(属性页\标签)控件及运用
  • swagger使用指引
  • 网站快速收录:如何优化网站H标签使用?
  • 【操作系统】同步与异步,同步与互斥
  • 【学习笔记】计算机图形学的几何数学基础知识
  • 【Redis】主从模式,哨兵,集群
  • 每日一题——小根堆实现堆排序算法
  • 低通滤波算法的数学原理和C语言实现
  • vim-plug的自动安装与基本使用介绍
  • 【学术征稿-组织单位 武汉理工大学西安理工大学、西安财经大学】第三届通信网络与机器学习(CNML 2025)
  • Codeforces Round 1002 (Div. 2)(部分题解)
  • 利用Python高效处理大规模词汇数据
  • MongoDB 聚合
  • 简易CPU设计入门:指令单元(三)
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.29 NumPy+Scikit-learn(sklearn):机器学习基石揭秘
  • DeepSeek蒸馏模型:轻量化AI的演进与突破
  • 测试csdn图片发布