ThreadLocal允许我们在线程中保存一些变量,但是做不到父子线程数据的共享
public class InheritThreadLocal { public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); // public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>(); public static void main(String args[]) throws InterruptedException { threadLocal.set(new Integer(123)); Thread thread = new MyThread(); thread.start(); Thread hread = new MThread(); hread.start(); System.out.println("main = " + threadLocal.get()); } static class MyThread extends Thread { @Override public void run() { System.out.println("MyThread = " + threadLocal.get()); new Thread(new Runnable() { public void run() { System.out.println("MyThread son = " + threadLocal.get()); } }).start(); } } static class MThread extends Thread { @Override public void run() { System.out.println("MThread = " + threadLocal.get()); } } }如这段代码,执行结果是
为什么子线程拿不到threadlocal中的数据,那是因为:
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }子线程拿到的是当前线程的threadlocal,而这个里面没有存储数据。
如果刚才的代码把注释的去掉,把注释下边那一行注释掉,执行结果是
这下子线程拿到threadlocal里面的数据了,这又是为什么呢
原因其实就是InheritableThreadLocal里面
ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; }子线程拿到的是继承过来的threadlocal里面的数据,也就是说它拿到了父线程刚才设置的数据,那这个inheritableThreadLocals又是什么时候设置进去的呢
private void init(ThreadGroup g, Runnable target, String name, long stackSize) { ..... if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID(); }注意if中的代码,创建线程的时候,都会去做这样的判断,如果inheritableThreadLocals里面有数据,就会将它复制到当前的threadlocal中
/** * Construct a new map including all Inheritable ThreadLocals * from given parent map. Called only by createInheritedMap. * * @param parentMap the map associated with parent thread. */ 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) { ThreadLocal key = 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++; } } } }
这下就明白了,如果是InheritableThreadLocal,它重写了Threadlocal中的getMap方法(上边贴代码了),在这个里面,它会拿到父线程threadlocal中的数据。
InheritableThreadLocal适用于子线程需要父线程中数据的情况