深度解析ThreadLocal

ThreadLocal使用方式为在一个线程中创建一个ThreadLocal对象,使用threadLocal.set()赋值,在相同线程的另一个地方使用threadLocal.get()获取值,接下来,从源码角度分析一下ThreadLocal的实现方式以及存在的问题。

1:创建是直接new 一个对象创建出来,既然ThreadLocal与线程已经绑定(一个ThreadLocal在不同的线程之中可以存放不同的值),接下来看下ThreadLocal与线程是如何进行绑定的

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

以上是ThreadLocal的set方法,先获取到当前的线程,然后通过getMap(t)获取到当前线程的ThreadLocalMap,ThreadLocalMap是ThreadLocal的静态内部类,在getMap()方法中可以看到ThreadLocalMap其实是Thread的一个属性(每一个线程都有自己专属的ThreadLocalMap)。

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

ThreadLocalMap其实就是一个Map类型的,其中key是ThreadLocal,value是Entity,Entity类的格式如下:

static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

ThreadLocalMap的其余地方可以不看,主要看下Entry!!!,此类继承了WeakRegerence(虚引用!!),其中此类的value就是我们要保存的值。

因此我们使用ThreadLocal.set方法保存一个值得时候,最终其实就是保存在每个线程专属的Map中,其中key为我们创建的ThreadLocal对象,这下可以明白为什么在多线程之中可以ThreadLocal可以保证线程安全,追踪到底其实就是将在不同线程之中set的值保存到了各自对应线程之中的Map之中,其中key就是ThreadLocal对象本身,也就解释了为什么一个ThreadLocal只能设置一个值,不允许设置多个值。

以上就是ThreadLocal 赋值的流程,如果把这个流程理解清楚,即使不看源码,想必大概get的方法也能猜到了,无非就是获取当前线程的ThreadLocalMap方法,然后通过此map的get(key)获取到值,其中key是当前的ThreadLocal对象。

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

以上是get()的源代码,与我们预想的差不多,只不过加了双重保险,获取的map是空的话会先初始化值进去再返回初始化之后的值,获取值的方法变为了ThreadLocalMap自定义的getEntry方法,获取Entry之后其属性value就是我们在ThreadLocal的set()方法中设置的值。

以上,ThreadLocal源码分析的差不多了,之前强调过的,为什么Entry要继承WeakReference,有什么作用,在此之前,需要了解强引用,软引用,弱引用相关知识点,不多赘述,网上找的一篇比较好的文章https://www.jianshu.com/p/825cca41d962

关于为什么使用弱引用,通过上面文章可知,弱引用的对象会在下一次垃圾收集器执行的时候被回收。如果我们不是使用弱引用,当在程序里我们把自己定义的threadLocal== null之后,下一次垃圾回收的时候,在Entry的key中还持有者对象的引用,因此我们创建的ThreadLocal不会被GC。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值