JAVA

关于 ThreadLocal 的定义及原理的实现

2019-05-31  本文已影响0人  qingwenLi

一、定义

       首先,ThreadLocal并不是一个Thread,这个类提供了线程局部变量也称为线程本地变量,它为变量在每个线程中创建了一个副本,通过这样的方式做到变量在线程间隔离且在方法间共享的场景。

二、实现原理

Threadlocal 的内部实现方法

Threadlocal 如何做到为每个线程维护变量副本

       我们先看一下set(T value)方法,在方法内部出现了一个ThreadLocalMap类,由于出现了Map冥冥之中感觉和链表应该是脱不开关系了,再接着看下一步的源码其不然。

    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 中有一个静态内部类 ThreadLocalMap,其内部维护着一张哈希表(Entry 数组),数组默认大小为 16,Entry 以弱引用的 ThreadLocal 作为 key/value。而Entry是继承WeakReference,和HashMap很大的区别是,Entry中没有next字段,所以就不存在链表的情况了。


图-1
public class ThreadLocal<T> {

 //静态内部类 ThreadLocalMap
 static class ThreadLocalMap {
       //
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }

//由于文章内容有限,这里省略部分源码
private static final int INITIAL_CAPACITY = 16;
// Entry 数组
private Entry[] table; 

    // 使用哈希表那么内部就牵涉到哈希因子,当表里的对象超过Threshold就会进行扩容
    private void setThreshold(int len) {
            threshold = len * 2 / 3;
          }
    }

}

在get函数中,首先获取到当前的线程t,再根据t获取ThreadLocalMap。

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

可以看到getMap是在当前线程中取得 ThreadLocalMap ,如果我们移步到Thread类中,每个线程都有的ThreadLocalMap类型变量threadLocals

  ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    // Thread类
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

如果map 不为空就把当前线程作为key拿到value,否则就初始化一个null值。

 private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

调用ThreadLocal的remove函数,手动删除不再需要的ThreadLocal,防止内存泄露。所以JDK建议将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。

     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

三、使用场景

四、与同步机制的对比

五、总结

上一篇 下一篇

猜你喜欢

热点阅读