ThreadLocal源码探析( 二 )

输出结果如下
线程名字:main---这是在主线程中线程名字:线程b---这是在线程b中线程名字:线程a---这是在线程a中线程名字:线程c---这是在线程c中Process finished with exit code 0可以看出每个线程各通过ThreadLocal对自己ThreadLocalMap中的数据存取并没有出现脏读的现象 。就是因为每个线程内部已经存储了ThreadLocal为Key变量副本为Vaule的键值对 。(隔离了)
可能你有点懵 , ThreadLocal是怎么把变量复制到Thread的ThreadLocalMap中的?
咱们接着唠...
 
当我们初始化一个线程的时候其内部干去创建了一个ThreadLocalMap的Map容器待用 。
public class Thread implements Runnable {    /* ThreadLocal values pertaining to this thread. This map is maintained     * by the ThreadLocal class. */    ThreadLocal.ThreadLocalMap threadLocals = null;}当ThreadLocalMap被创建加载的时候其静态内部类Entry也随之加载 , 完成初始化动作 。
 static class Entry extends WeakReference<ThreadLocal<?>> {        /** The value associated with this ThreadLocal. */       Object value;        Entry(ThreadLocal<?> k, Object v) {            super(k);            value = v;        }}到此 , 线程Thread内部的Map容器初始化完毕 , 那么它又是如何和ThreadLocal产生关系 , ThreadLocal又是如何管理键值对的关系 。
【ThreadLocal源码探析】 
ThreadLocal探析我们就其核心方法分析一下内部的逻辑 , 同时解答上述存在的疑问:

  • set()方法用于保存当前线程的副本变量值 。
  • get()方法用于获取当前线程的副本变量值 。
  • initialValue()为当前线程初始副本变量值 。
  • remove()方法移除当前线程的副本变量值 。
set方法/** * Sets the current thread's copy of this thread-local variable * to the specified value.  Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of *        this thread-local. */public void set(T value) {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null)        map.set(this, value);    else        createMap(t, value);}ThreadLocalMap getMap(Thread t) {    return t.threadLocals;}void createMap(Thread t, T firstValue) {    t.threadLocals = new ThreadLocalMap(this, firstValue);}解说一下你就懂了:
当我们在Thread内部调用set方法时:
  • 第一步会去获取调用当前方法的线程Thread 。
  • 然后顺其自然的拿到当前线程内部的ThreadLocalMap容器 。
  • 最后就把变量副本给丢进去 。
没了...懂了吗 , ThreadLocal(就认为是个维护线程内部变量的工具!)只是在Set的时候去操作了Thread内部的·ThreadLocalMap将变量拷贝到了Thread内部的Map容器中 , Key就是当前的ThreadLocal,Value就是变量的副本 。
get方法/** * Returns the value in the current thread's copy of this * thread-local variable.  If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */public T get() {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null) {        ThreadLocalMap.Entry e = map.getEntry(this);        if (e != null)            return (T)e.value;    }    return setInitialValue();}ThreadLocalMap getMap(Thread t) {    return t.threadLocals;}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;}protected T initialValue() {    return null;}


推荐阅读