InheritableThreadLocal
[TOC]
一、简介
在Thread
中除了有属性threadLocals
引用ThreadLocal.ThreadLocalMap
,其实还有一个属性,也就是inheritableThreadLocals
,threadLocals
的作用是保存本地线程变量,而inneritableThreadLocals
的作用是传递当前线程本地变量InheritableThreadLocal
到子线程的本地变量InheritableThreadLocal
中。
二、实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static void main(String[] args) throws InterruptedException { InheritableThreadLocal<String> username = new InheritableThreadLocal<>(); ThreadLocal<String> password = new ThreadLocal<>(); username.set("zhangShang"); password.set("123456789");
new Thread(new Runnable() { @Override public void run() { System.out.println(username.get()); System.out.println(password.get()); } }).start(); }
|
输出结果为:
所以基本上可以得出结论:InheritableThreadLocal
是具有父子线程传递的,而ThreadLocal
不具有父子线程传递的功能。
三、原理
1. InheritableThreadLocal
的实现
InheritableThreadLocal
继承于ThreadLocal
,并重写了ThreadLocal
中的三个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) { return parentValue; }
ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; }
void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); } }
|
2.线程的创建过程
跟踪new Thread()
方法。
1.进入初始化方法。
1 2 3
| public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); }
|
2.调用init
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| private void init(ThreadGroup g, Runnable target, String name,long stackSize) { init(g, target, name, stackSize, null, true); }
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; Thread parent = currentThread(); ... 省略一些与本章无关代码 if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); this.stackSize = stackSize;
tid = nextThreadID(); }
|
3.进入创建方法createInheritedMap
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { return new ThreadLocalMap(parentMap); }
private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new Entry[len];
for (int j = 0; j < len; j++) { Entry e = parentTable[j]; if (e != null) { @SuppressWarnings("unchecked") ThreadLocal<Object> key = (ThreadLocal<Object>) e.get(); if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len - 1); while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } }
|
四、思考
上面说父子进程通过inheritableThreadLocals
属性来传递本地变量,在实际的应用场景中,一般不会出现父进程直接创建子进程的情况,一般都是采用线程池的方式,如果采用线程池那么inheritableThreadLocal
还会有效吗?读者可以考虑一下,写个demo
跑一下,看看具体的情况,下一篇文章将进行解答。