• 探秘ThreadLocal


    一 类结构

     主要是set(T), get(), remove()方法

     二  TheadLocal是什么时候创建的

       threadLocal的初始化, lazy creating, 用到的时候(get 或者 set)再初始化

          

                  

    void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);// this 指代的是theadlocal
    }
    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;
    }
    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();
    }
    public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
    map.set(this, value);
    else
    createMap(t, value);
    }
    
    
    

    三 TheadLocal 是如何保存的

    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
    }

    初始化时,threadlocal作为第一个key,

    由ThreadLocal中的 createMap方法和set方法 new ThreadLocalMap(this, firstValue) 结合 
    public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
    map.set(this, value);
    else
    createMap(t, value);
    }
    private void set(ThreadLocal<?> key, Object value) {

    // We don't use a fast path as with get() because it is at
    // least as common to use set() to create new entries as
    // it is to replace existing ones, in which case, a fast
    // path would fail more often than not.

    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);

    for (Entry e = tab[i];
    e != null;
    e = tab[i = nextIndex(i, len)]) {
    ThreadLocal<?> k = e.get();//threadLocal的实际引用地址。

    if (k == key) {
    e.value = value; //第N次set,将线程变量值实际存入Entry,ThreadLocalMap中维护由Entry组成的数组
    return;
    }

    if (k == null) {
    replaceStaleEntry(key, value, i);//第一次set
    return;
    }
    }

    tab[i] = new Entry(key, value);
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
    rehash();
    }
    上文的代码解读:由于Entry继承自WeakReference,所以e.get()指代的是TheadLocal的实际引用地址。

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

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

     以上代码就是变量值是如何存入的,下面来看怎么取出线程变量值

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

    private Entry getEntry(ThreadLocal<?> key) {
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if (e != null && e.get() == key)
    return e;
    else
    return getEntryAfterMiss(key, i, e);
    }

     总结,线程变量threadLocal是通过自定义实现的hash存于TheadLocalMap中的Entry数组的。

    四 TheadLocal是如何销毁的

       

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

    结束语

    为什么要用WeakReference, 当threadlocal最后一次被get后, 就不会再有引用指向threadlocal了,从而ThreadLocalMap中的Entry所存的变量值就可以被GC回收了。

    在使用完线程变量后, 一定要及时清理,remove,尤其是在使用线程池的情况下。否则会造成内存溢出。

  • 相关阅读:
    Perl 常用的小细节总结
    Linux-root管理员创建新用户
    Linux-普通用户和root用户任意切换
    Linux-设置终端界面的字体颜色和自定义常用快捷功能
    Linux命令行好玩的命令
    如何配一副好的眼镜
    linux下面升级 Python版本并修改yum属性信息
    mysql远程登陆
    Linux 如何找到100M以上的大文件
    将raspberry 3B+的apt替换为国内源
  • 原文地址:https://www.cnblogs.com/shoubianxingchen/p/11031616.html
Copyright © 2020-2023  润新知