ThreadLocal简析

2020-04-29  本文已影响0人  MadnessXiong

1. ThreadLocal简介

顾名思义,ThreadLocal的功能就是为每一个使用局部变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他的线程副本冲突。从线程的角度讲,就好像每一个线程都完全拥有该变量。

2. ThreadLocal源码简析

2.1 ThreadLocal如何维护变量

既然ThreadLocal让每一个线程都拥有自己的变量,那么就需要维护此变量,在ThreadLocal类中,有一个内部类ThreadLocal.ThreadLocalMap来负责此工作:

static class ThreadLocalMap {   
                /**
                * 定义一个弱引用Entry类,用来保存ThreadLocal和value之间的关系
                * 之所以用弱引用,是为了解决线程与ThreadLocal之间的强绑定关系,如果线程没有被回收,GC也可以回收这个对            * 象
                */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;

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

ThreadLocalMap内部通过一个Entry来保存ThreadLocal和value之间的关系,Entry是一个弱引用,用来防止内存泄漏

2.2 ThreadLocal的set():

    public void set(T value) {
        //获取当前线程
        Thread t = Thread.currentThread();
        //根据当前线程获取ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
            //存储
            map.set(this, value);
        else
            createMap(t, value);
    }
        //创建一个ThreadLocalMap
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
        //获取ThreadLocalMap
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

首先看createMap(),在这个方法中,构造了一个ThreadLocalMap,将ThreadLocal本身和要绑定的变量传入,然后将构造好的ThreadLocalMap赋值给了当前线程t,也就是说当前线程t持有了ThreadLocalMap对象。而这个ThreadLocalMap对象绑定了当前ThreadLocal和变量,形成了Thread->ThreadLocal->变量之间的绑定关系。

再看set()本身,首先获取当前线程t,根据当前线程t去获取当前的ThreadLocalMap,上面说过,当前线程t持有了当前ThreadLocalMap。所以假如ThreadLocalMap已创建,是可以获取到的。如果没创建就去创建。如果创建了就调用ThreadLocalMap.set()将当前ThreadLocal和变量绑定。

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

get()中首先获取了当前线程t,然后通过getMap(),获取了当前线程的ThreadLocalMap,然后再通过map.getEntry(this),传入当前ThreadLocal取出与之绑定的变量。

上一篇下一篇

猜你喜欢

热点阅读