Use ThreadLocal Example
// create static global reference s1(type: ThreadLocal)public static ThreadLocals1 = new ThreadLocal ();// then set value in thread (just which thread run it)s1.set("value");// then you can get the value where the thread is running s1.get();//在线程池环境中需要手动移除它,(线程终止会自动移除ThreadLocal,但线程池的线程还会继续使用)s1.remove()
The Magic of ThreadLocal
只有一个静态引用(s1),但是却可以在不同的线程中取到不同的值,why?
先看一下 set
方法
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); //从这里可以看出 每个线程对应一个 ThreadLocalMap if (map != null) map.set(this, value); else createMap(t, value); }// 先来看初次赋值void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); // threadLocals 线程的内部变量 }// ThreadLocalMap 的构造方法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); }
- 每个线程对应一个 ThreadLocalMap
- ThreadLocalMap的key 的值就是 ThreadLocal 本身(s1),value 就是
set
传入的值
我们再来看一下 get
方法
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); //取出(s1)对应的值 if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
get
方法就是简单的取值
Deep In TheadLocal (weakReference and weakHashMap)
我们从上面知道 ThreadLocalMap 是线程存储ThreadLocal的地方,它类似于WeakHashMap:
/** * 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> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } }
上面我们看到,entry 的key 存储的是ThreadLocal (s1)的应用,但是这个引用是个弱引用:
key -------(弱引用)----->> ThreadLocal Instance <<------强引用 -------s1
所以如果 s1=null,那么 ThreadLocal Instance 是会被回收的
so why we should use WeakReference?
InheritableThreadLocal
作用就是在子进程中可以取到父进程的ThreadLocal的值。
/* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
InheritableThreadLocal 也只是存储在 ThreadLocalMap 里的
InheritableThreadLocal which subclasses ThreadLocal class is used in such situations. This class has only one method 'protected Object childValue(Object parentValue)' which is used to set the initial value of the InheritableThreadLocal variable in the child thread as a function of a ThreadLocal variable (passed as a parameter) in the parent thread. This method is called from within the parent thread before the child thread is created and the default implementation will make the child values identical to parent's, but we can override the childValue() method to set the child value as a function of the parent value for those ThreadLocals which have values in the parent thread. By default the childValue() returns the same input argument, but again an override of the childValue method might change this behavior as well.
唯一的疑问就是什么时候给子线程的inheritableThreadLocals 变量赋的值,就是在父进程创建子进程的时候 调用的 childValue(Object parentValue) 方法。
More
思考:涉及到线程池 和异步操作的时候要怎么传递ThreadLocal?
参考: