源码分析--ThreadLocal(图解)

想清楚ThreadLocal源码的原理,那么先搞明白 ThreadLocalMap ,很关键

1.首先我们知道Thread 里面有一个ThreadLocalMap ;

 public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
 }

2.ThreadLocalMap里面有包含了一个成员变量Entry[] table。

static class ThreadLocalMap {
    
     private Entry[] table;
     
    //Entry继承了WeakReference<ThreadLocal<?>>, 说明Entry 持有一个指向ThreadLocal的弱引用。
    //弱引用,就是如果一个对象只有弱引用指向它,下一次JVM垃圾回收的时候一定会被回收调。
    static class Entry extends WeakReference<ThreadLocal<?>> {
        //这个value就是存放我们的数据
         Object value;
        
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    ///...省略部分源码
  }

上面的1,2代码反应了如下关系

  • 一个Thread里面包含了一个ThreadLocalMap
  • 一个ThreadLocalMap包含了一个table
  • table是一个Entry数组
  • Entry数组有一个value存放数据,reference弱引用可以指向某个ThreadLocal
    在这里插入图片描述
  1. ThreadLocalMap包含了一个Entry[] table, 其实ThreadLocalMap是底层数据结构就是一个Entry数组。
    ThreadLocalMap是一个Map,Entry代表一个哈希槽。
    Entry的key(键)其实就是reference, 而value(值)就是上面的value.
    在这里插入图片描述

ThreadLocalMap存值原理:
1.就是通过Entry的 key的Hash值计算出Index
2.找到数组的Index位置,如果该位置为空就存放Entry
3.不为空则Index ++,直到找到一个空的位置存放 (这里还有一个扩容的问题,暂不讨论)

ThreadLocalMap取值原理:
1.就是通过 key的Hash值计算出Index
2.找到Index的位置Entry,再对比一下Entry的key和需要查找的key是不是相等,相等则取出value
3.不相等则Index++,然后重复第2步骤

总结:每个Thread 对象里面有一个ThreadLocalMap。ThreadLocalMap是一个Map, key是ThreadLocal类型的数据, value存放数据

4.TheadLocal 的set方法

public class ThreadLocal<T> {
    public void set(T value) {
        //1.获取当前线程的ThreadLocalMap(就是上面说的ThreadLocalMap)
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            // ThreadLocalMap是一个Map, key是ThreadLocal类型的数据, value存放数据
            // 2.map 不为空, Map的key是this对象本身,value是我们存放的数据。
           //可能会疑惑,为什么key存放this?下面再详细说明
            map.set(this, value);
        else
        //3.map 为空,为当前线程创建一个Map
            createMap(t, value);
    }
}

源码为什么key存放this?
1.一个Thread有一个ThreadLocalMap,而ThreadLocalMap可以存放多个Entry { “key”:ThreadLocal :“value”: object }

2.如下测试代码所示,当我们在线程A里面操作threadLocal1.set(1),
其实就是在线程A自己的ThreadLocalMap的 Entry{ “key”:threadLocal1 :“value”: 1}。
反之, 线程B就是线程B自己的ThreadLocalMap 的 Entry{ “key”:threadLocal1 :“value”: 2}。

public class ThreadLocalTest {

    static ThreadLocal<Integer> threadLocal1 = new ThreadLocal<>();

    static ThreadLocal<Integer> threadLocal2 = new ThreadLocal<>();

    public static void main(String[] args) {

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    threadLocal1.set(1);
                    threadLocal2.set(2);
                }finally {
                    threadLocal1.remove();
                    threadLocal2.remove();
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    threadLocal1.set(1);
                    threadLocal2.set(2);
                }finally {
                    threadLocal1.remove();
                    threadLocal2.remove();
                }
            }
        });

        threadA.start();
        threadB.start();
    }
}

最后数据存放图如下(table里面entry存放数据的位置只是假设,threadLocal1 存放的位置还是通过它的Hash值求出的Index所得 ):
在这里插入图片描述
5.ThreadLocal的get方法( 如果看懂上面的set方法,这里就很简单了)

public T get() {
     //1.获取当前线程的ThreadLocalMap(就是上面说的ThreadLocalMap)
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        //map 不为空,根据this获取Entry 
        ThreadLocalMap.Entry e = map.getEntry(this);
       //e不为空,返回e.value
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
private T setInitialValue() {
    //initialValue() 就是返回了一个null
    T value = initialValue();
    Thread t = Thread.currentThread();
    //获取当前线程的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null)
        //map 不为空,设置值为null
        map.set(this, value);
    else
        //map 为空,创建一个map,并设置值为null
        createMap(t, value);
    return value;
}

6.ThreadLocal的数据用完后记得使用 threadLocal.remove()移除数据,不然在某种情况下可能会导致内存泄漏(如图下描述)
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
FastThreadLocal 是 Netty 中的一个优化版 ThreadLocal 实现。与 JDK 自带的 ThreadLocal 相比,FastThreadLocal 在性能上有所提升。 FastThreadLocal 的性能优势主要体现在以下几个方面: 1. 线程安全性:FastThreadLocal 使用了一种高效的方式来保证线程安全,避免了使用锁的开销,使得在高并发场景下性能更好。 2. 内存占用:FastThreadLocal 的内部数据结构更加紧凑,占用的内存更少,减少了对堆内存的占用,提高了内存的利用效率。 3. 访问速度:FastThreadLocal 在访问时,使用了直接索引的方式,避免了哈希表查找的开销,使得访问速度更快。 在 Netty 源码中,FastThreadLocal 主要被用于优化线程的局部变量存储,提高线程之间的数据隔离性和访问效率。通过使用 FastThreadLocal,Netty 在高性能的网络通信中能够更好地管理线程的局部变量,提供更高的性能和并发能力。 引用中提到的代码片段展示了 Netty 中的 InternalThreadLocalMap 的获取方式。如果当前线程是 FastThreadLocalThread 类型的线程,那么就直接调用 fastGet 方法来获取 InternalThreadLocalMap 实例;否则,调用 slowGet 方法来获取。 fastGet 方法中,会先尝试获取线程的 threadLocalMap 属性,如果不存在则创建一个新的 InternalThreadLocalMap,并设置为线程的 threadLocalMap 属性。最后返回获取到的 threadLocalMap。 slowGet 方法中,通过调用 UnpaddedInternalThreadLocalMap.slowThreadLocalMap 的 get 方法来获取 InternalThreadLocalMap 实例。如果获取到的实例为 null,则创建一个新的 InternalThreadLocalMap,并将其设置到 slowThreadLocalMap 中。最后返回获取到的 InternalThreadLocalMap。 综上所述,FastThreadLocal 是 Netty 中为了优化线程局部变量存储而设计的一种高性能的 ThreadLocal 实现。它通过减少锁的开销、优化内存占用和加快访问速度来提升性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [FastThreadLocal源码分析](https://blog.csdn.net/lvlei19911108/article/details/118021402)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Netty 高性能之道 FastThreadLocal 源码分析(快且安全)](https://blog.csdn.net/weixin_33871366/article/details/94653953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值