ThreadLocal源码简读

先说一下,本篇文章,只是简单,阅读下源码,应对面试差不多够了,要深入理解,还请看源码

讲实话,看完源码,还是有点小迷,ThreadLocal源码,感觉优点乱。。

每个线程中都可以通过ThreadLocal定义一个独立的副本,不会影响到其他线程;

ThreadLocal主要属性和方法

  1. 一个静态内部类:ThreadLocalMap

    • 维护了一个静态内部类Entry,Entry类下有一个value属性,就是存储线程通过ThreadLocal放的值;

    • 维护了一个Entry[ ] table数组;

      此数组里面存放的是线程对象;

    • 这里注意:Entry是弱引用,最后会说一下,弱引用使用场景;

  2. get方法,后面说

  3. set方法,后面说

下面是提取出来的主要的源码:

public class ThreadLocal<T> {
    static class ThreadLocalMap {
        // 每个线程一个Entry,对应唯一的Value,弱引用对象
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        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);
        }
    }
    // 设置值,后面讲
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    // 主要是getEntry方法!后面会详解
    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();
    }
    // 我们在set值的时候,ThreadLocalMap一般是没有创建的
    // 而是通过createMap(t, value);创建一个
    // 这个初始化,会直接通过构造方法,把要放的值,放进去!
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    // 删除,直接删除线程对应的Entry对象
    public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread());
        if (m != null)
            m.remove(this);
    }
}

还要知道:

每一个Thread对象下都有一个ThreadLocalMap对象:

public class Thread implements Runnable {
	ThreadLocal.ThreadLocalMap threadLocals = null;
  	......
}

get、set

  1. ThreadLocalMap下维护一个table数组,初始容量为16;

  2. 提供set()方法:

    根据线程对象,拿到此TheadLocal下的ThreadLocalMap对象

    ThreadLocalMap对象只有一个!

    map.getEntry根据线程ID,锁定线程对应的Entry对象;

    找到这个Entry对象,拿到里面的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();
    }
    
  3. set()方法

    比较简单;不说了。。

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value); // 这里是key是线程对象,value是要村的值
        else
            createMap(t, value);
    }
    

弱引用Entry

Entry对象是弱引用!!存在内存泄露风险!

弱引用:GC触发,就会回收的对象!

所以,只能用于临时存储,即存即用的场景,如果是强依赖这个副本,则不适合使用ThreadLocal

原文地址:https://www.cnblogs.com/mussessein/p/12762087.html