ThreadLocal 杂谈

作者: hello_steam | 来源:发表于2017-06-10 15:29 被阅读16次

    ThreadLocal 是为多线程服务的。本质上ThreadLocal是一个关于创建线程局部变量的类。
    通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。举个例子, 服务器同时被100个用户访问,访问的时候需要对用户信息进行操作,这里threadLocal就可以用来对这100个用户信息进行thread级别的隔离。

    ThreadLocal是如何做到变量只能被当前线程访问呢?

    首先需要声明的是thread local是通过给thread创建变量副本的方式来存储变量的。这些需要被线程使用到的变量就是存储在thread对象的threadLocals属性上。

    这里又要提到ThreadLocalMap,这个是threadlocals的类型。从这个角度来看ThreadLocal类更像是一个util类,主要的职责就是帮助thread管理threadLocals属性。

    变量存储

    利用threadlocal对象 set 变量到thread上时调用的set方法源码是通过获取当前thread上绑定的threadlocals属性的值来进行操作,最终所有的值真正存储的位置其实都在thread本身与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);
    }
    

    再来看get方法:

    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();
    }
    

    这里的设计就有点意思了,首先先从thread上拿到了threadlocals属性,这是一个ThreadLocalMap类型的值,也是数据真实的存储位置。thread所关联的所有threadlocal其实都存在这个map的entry里,也就是说不管这个thread里持有了多少个threadlocal实例,变量副本存储的地方有且只有一个map的entry。

    每个Thread 维护一个 ThreadLocalMap 映射表,这个映射表的 key 是 ThreadLocal 实例本身,value 是真正需要存储的 Object。
    也就是说 ThreadLocal 本身并不存储值,它只是作为一个 key 来让线程从 ThreadLocalMap 获取 value。值得注意的是图中的虚线,表示 ThreadLocalMap 是使用 ThreadLocal 的弱引用作为 Key 的,弱引用的对象在 GC 时会被回收。

    threadlocal的存在是为了帮助thread进行threadlocals属性的关于制定key(threadllocal其实就是threadlocalMap的key)的赋值和取值。多线程之间的threadlocal实例本身其实是共享的,所以使用的时候一般定义成static变量,达到thread间共享实例的目的。

    相关文章

      网友评论

        本文标题:ThreadLocal 杂谈

        本文链接:https://www.haomeiwen.com/subject/yktcqxtx.html