ThreadLocal<T>

ThreadLocal<>适用于什么场景?

  1. 每个线程都有自己的拷贝实例,其他线程不能访问。
  2. 方便在线程内部传递。
    其实可以在线程内部new一个对象来实现这个需求,但是这样会产生大量的样板代码,这样ThreadLocal就应运而生了。

怎么用?来个栗子

public class SessionHandler {
    private static ThreadLocal<Session> threadLocal = ThreadLocal.withInitial(() -> null);
    private static ThreadLocal<Session> another = new ThreadLocal() {
        protected Session initialValue() {
            return null;
        }
    };

    public Session get() {
        return threadLocal.get();
    }

    public void set(Session session) {
        threadLocal.set(session);
    }

    public void remove() {
        threadLocal.remove();
    }
}

原理是什么?需要游向代码深水区一探究竟。

public class ThreadLocal<T> {
    protected T initialValue() {
        return null;
    }    


    static class ThreadLocalMap {
        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

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

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


    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 class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
}

原来Thread内部有一个成员ThreadLocal.ThreadLocalMap threadLocals,所以每个线程都有自己的map,这样就不会冲突。这个map类似HashMap,本质是一个Entry[],key和value都存储在Entry里,key是ThreadLocal,value是泛型。这个map不会发生哈希碰撞。
为什么要构建一个map,因为thread可能需要多个threadLocal,那这些threadLocal会冲突吗?
还有会造成内存泄露吗?

参考:ThreadLocal和ThreadLocalMap源码分析

推荐阅读更多精彩内容