ThreadLocal (二):什么时候使用 InheritableThreadLocal

一、ThreadLocal 在父子线程传递的问题

public class InheritableThreadLocalDemo {

//    全局变量
//    static ThreadLocal<String> threadLocal = new ThreadLocal<>();
    static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();


    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                InheritableThreadLocalDemo.threadLocal.set("superWorld");
                new Service().call();
            }
        }).start();
    }
}


class Service {
    public void call() {
        System.out.println("Service:" + Thread.currentThread().getName() + " : " + InheritableThreadLocalDemo.threadLocal.get());
        //new Dao().call();
        new Thread(new Runnable() {
            @Override
            public void run() {
                new Dao().call();
            }
        }).start();
    }
}

class Dao {
    public void call() {
        System.out.println("Dao:" + Thread.currentThread().getName() + " : " + InheritableThreadLocalDemo.threadLocal.get());
    }

}

 

 

二、InheritableThreadLocal 和 ThreadLocal 的区别

1. InheritableThreadLocal 实现

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    /**
     * Computes the child's initial value for this inheritable thread-local
     * variable as a function of the parent's value at the time the child
     * thread is created.  This method is called from within the parent
     * thread before the child is started.
     * <p>
     * This method merely returns its input argument, and should be overridden
     * if a different behavior is desired.
     *
     * @param parentValue the parent thread's value
     * @return the child thread's initial value
     */
    protected T childValue(T parentValue) {
        return parentValue;
    }

    /**
     * Get the map associated with a ThreadLocal.
     *
     * @param t the current thread
     */
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }

    /**
     * Create the map associated with a ThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the table.
     */
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

  

2. ThreadLocal 的getMap、createMap实现

    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

 

通过上面的代码我们可以看到InheritableThreadLocal 重写了childValue, getMap,createMap三个方法,

当我们往里面set值的时候,值保存到了inheritableThreadLocals里面,而不是之前的threadLocals。

 

三、问题:为什么当创建子线程时,可以获取到上个线程里的threadLocal中的值呢?

原因就是在新创建线程的时候,会把之前线程的inheritableThreadLocals赋值给新线程的inheritableThreadLocals,通过这种方式实现了数据的传递。

代码关键点:

1. Thread#init

if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =  ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

 

 

2. ThreadLocal.createInheritedMap

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

 

posted @ 2014-09-20 17:42  等风来。。  Views(358)  Comments(0Edit  收藏  举报
------------------------------------------------------------------------------------------------------------ --------------- 欢迎联系 x.guan.ling@gmail.com--------------- ------------------------------------------------------------------------------------------------------------