超简单的ThreadLocal

  多线程访问同一个共享变量的时候容易出现并发问题,很多时候我们是通过加锁解决的。但是,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。那么这就要提到 ThreadLocal 了。比如很多公司做单点登录会用到 ThreadLocal ,通过拦截 token 去获取当前登录信息。

复制代码
ThreadLocal<Integer> local = new ThreadLocal<>();

new Thread(()->{
    local.set(7);
    System.out.println(local.get());
}).start();

new Thread(()->{
    local.set(5);
    System.out.println(local.get());
}).start();
复制代码

get/set

复制代码
public void set(T value) {
    //获取当前线程
    Thread t = Thread.currentThread();
    //获取当前线程的成员变量ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    //如果map不为空
    if (map != null)
        //将值设置到map中,key是this,即threadLocal对象,value是传入的value值
        map.set(this, value);
    else
       //如果map为空,则需要创建新的map对象
        createMap(t, value);
}


public T get() {
    //获取当前线程
    Thread t = Thread.currentThread();
    //获取当前线程的成员变量ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        //根据threadLocal对象从map中获取Entry对象
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            //获取保存的数据
            T result = (T)e.value;
            return result;
        }
    }
    //初始化数据
    return setInitialValue();
}
复制代码

  可以看到 ThreadLocal 的 get/set 就是操作的 ThreadLocalMap ,它里面有一个entrty[], entrty 用线程的引用做key,entrty 本身还继承了extends WeakReference 是一个弱引用,无论内存是否充足都会回收它,由此来解决内存溢出的问题。我们使用 ThreadLocal 的时候一般会 static,当弱引用被强引用使用的时候,这个弱引用则不会被回收,防止我们线程在使用时,threadlocal 被清空了。

resize

 

复制代码
//  在 set 的时候会将 size+1,若 >= threshold 则执行 rehash();
// threshold = threshold * 2/3
private void set(ThreadLocal<?> key, Object value) {
    .....
    
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        rehash();
}


private void rehash() {
    // 扩容前先清理一波 key=null 的。
    expungeStaleEntries();

    // 如果回收之后的size大于等于threshold的3/4时,才需要真正的扩容
    if (size >= threshold - threshold / 4)
        // resize中每次都是按2倍的大小扩容
        resize();
}
复制代码

 

  

 

posted @   吴磊的  阅读(83)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
//生成目录索引列表
点击右上角即可分享
微信分享提示