ThreadLocal源码解析

ThreadLocal的原理核心就是理顺Thread,ThreadLocal以及ThreadLocalMap三者之间的关系。即每个Thread对象中都持有一个ThreadLocalMap成员变量,ThreadLocalMap可以持有多个ThreadLocal和对应的value。当往ThreadLocalMap 设置值时候,key是threadLocal本身。

  • 每个Thread对象中都持有一个ThreadLocalMap成员变量
  • ThreadLocalMap可以持有多个ThreadLocal和对应的value
  • ThreadLocal源码解析

    下面,通过对其核心的三个方法的流程来理解其实现过程。

    initialValue()方法处理流程分析

    initialValue()方法会返回当前线程对应的“初始值”,这是一个延迟加载的方法,只有在调用get的时候,才会触发当线程第一次使用get方法访问变量时,将调用此方法。但是如果线程调用了set方法,在这种情况下,不会调用initialValue方法了。

    <code>protected T initialValue() {

        return null;

    }/<code>

    默认的initialValue方法是没做任何事情的,所以我们要重写initialValue方法,就像前面的例子。

    Set流程分析

    Set方法是设置值。

    Threadlocal.set()

    <code>public void set(T value) {
         //获取当前线程
    Thread t = Thread.currentThread();
    //通过当前线程,获取当前线程中的ThreadLocalMap
        ThreadLocalMap map = getMap(t);

        if (map != null)
    //如果ThreadLocalMap已经存在,则将值传进去
            map.set(this, value);
        else
    //如果ThreadLocalMap不存在,则创建ThreadLocalMap
            createMap(t, value);
    }/<code>

    这里设置值是设置到Thread的ThreadLocalMap中,所以需要获取当前的Thread。

    Threadlocal.getMap方法

    <code>ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
    }/<code>

    这个方法很简单,就是获取线程中的成员变量ThreadLocalMap

    在Thread中成员变量threadLocals就是ThreadLocal.ThreadLocalMap 类型,初始值为null。

    Threadlocal.createMap方法

    <code>void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
    }/<code>

    可以看到,createMap方法就是为Thread的成员变量threadLocals 创建实例。并将需要设置的值放进map中。key就是threadlocal本身,value是需要保存的值。

    Get流程分析

    Get获取设置的值

    ThreadLocal.get方法

    <code>public T get() {
    //获取当前的线程
    Thread t = Thread.currentThread();
    //通过当前线程,获取当前线程中的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    //如果ThreadLocalMap不为空,获取值
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null) {
    @SuppressWarnings("unchecked")
    T result = (T)e.value;
    return result;
    }
    }
    //如果ThreadLocalMap为空,返回初始值
    return setInitialValue();
    }/<code>

    这里要注意的是Entry 继承了弱引用类型,使用弱引用类型的目的是为了避免已经无用的数据占用内存空间。当一个对象仅仅被weak reference指向, 而没有任何其他强引用指向, GC运行时候这个对象就会被回收。

    Threadlocal.Entry 类型

    <code>static class Entry extends WeakReference<threadlocal>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal> k, Object v) {
    super(k);
    value = v;
    }
    }/<threadlocal>/<code>
    <code>弱引用也是关键的知识。下面的代码可以测试弱引用是否有强引用时候的区别 

    public class TestWeakReference {
    public static void main(String[] args) {
    Car car = new Car(22000,"silver");
    WeakReference weakCar = new WeakReference(car);
    int i=0;
    while(true){
    if(weakCar.get()!=null){
    i++;
    System.out.println("Object is alive for "+i+" loops - "+weakCar);
    }else{
    System.out.println("Object has been collected.");
    break;
    }
    }
    //如果有下面这一句,car就不会被回收。因为被强应用指向了
    //System.out.println(car);
    }
    }
    /<code>

    如果注释掉打印“System.out.println(car)”这一行,过了一段时间GC后,会获取到null的car值,然后会打印“Object has been collected.”



    分享到:


    相關文章: