`

InheritableThreadLocal 源码分析

阅读更多

/*
* Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/

package com.hanlin.fadp;
import java.lang.ref.*;

/**
* This class extends <tt>ThreadLocal</tt> to provide inheritance of values
* from parent thread to child thread: when a child thread is created, the
* child receives initial values for all inheritable thread-local variables
* for which the parent has values.  Normally the child's values will be
* identical to the parent's; however, the child's value can be made an
* arbitrary function of the parent's by overriding the <tt>childValue</tt>
* method in this class.
*
* <p>Inheritable thread-local variables are used in preference to
* ordinary thread-local variables when the per-thread-attribute being
* maintained in the variable (e.g., User ID, Transaction ID) must be
* automatically transmitted to any child threads that are created.
*
* @author  Josh Bloch and Doug Lea
* @see     ThreadLocal
* @since   1.2
*/

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    /**
     * 这个方法留给子类实现
     *
     * @param parentValue the parent thread's value
     * @return the child thread's initial value
     */
    protected T childValue(T parentValue) {
        return parentValue;
    }


    /**
     * 重写getMap方法,返回的是Thread的inheritableThreadLocals引用
     *
     * @param t the current thread
     */
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }


    /**
     * 重写createMap方法,构造的ThreadLocalMap会传给Thread的inheritableThreadLocals 变量
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the table.
     * @param map the map to store.
     */
   void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }

}


它是如何实现父子线程间 ThreadLocal 传递的了?


首先,重写了 getMap 和 createMap 方法,因为 ThreadLocal 在执行 set 方法或者 get 方法的时候,会用到.




是不是发现了啥?这里使用的是 inheritableThreadLocals,而不再是 ThreadLocal 中的 threadLocals.

再看 Thread 类的 init 方法:

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name.toCharArray();

    Thread parent = currentThread();
    SecurityManager security = System.getSecurityManager();
    if (g == null) {
        /* Determine if it's an applet or not */

        /* If there is a security manager, ask the security manager
           what to do. */
        if (security != null) {
            g = security.getThreadGroup();
        }

        /* If the security doesn't have a strong opinion of the matter
           use the parent thread group. */
        if (g == null) {
            g = parent.getThreadGroup();
        }
    }

    /* checkAccess regardless of whether or not threadgroup is
       explicitly passed in. */
    g.checkAccess();

    /*
     * Do we have the required permissions?
     */
    if (security != null) {
        if (isCCLOverridden(getClass())) {
            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
    }

    g.addUnstarted();

    this.group = g;
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    if (security == null || isCCLOverridden(parent.getClass()))
        this.contextClassLoader = parent.getContextClassLoader();
    else
        this.contextClassLoader = parent.contextClassLoader;
    this.inheritedAccessControlContext =
            acc != null ? acc : AccessController.getContext();
    this.target = target;
    setPriority(priority);
    // 这里 inheritableThreadLocals 将不再为空,ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 语句会把父类中的 ThreadLocal 中的值拷贝一份到子类中.
    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();
}


说明:父子线程 ThreadLocal 在拷贝的时候,拷贝的是引用,也就是说如果父线程修改了 ThreadLocal 中的某个对象,那么子线程中 ThreadLocal 的值也会跟着变.


理论分析:




测试:
package com.hanlin.fadp;

public class InheritableThreadLocalTest {


    static class Person{
        String name;

        public Person(String name) {
            this.name = name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    public static ThreadLocal<Person> inheritableThreadLocal = new InheritableThreadLocal<Person>();

    static CountDownLatch latch = new CountDownLatch(1);

    public static void main(String args[]) throws InterruptedException {

        Person tom = new Person("tom");
        inheritableThreadLocal.set(tom);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    Person p = inheritableThreadLocal.get();
                    p.setName("sdsds");

                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("子线程<InheritableThreadLocal>:" + inheritableThreadLocal.get());
                latch.countDown();
            }
        }, "AAAAA").start();
        System.out.println("父线程<InheritableThreadLocal>:" + inheritableThreadLocal.get());

        Thread.sleep(1000);

//        Person p = inheritableThreadLocal.get();
//        p.setName("sdsds");
//        inheritableThreadLocal.set(p);

        latch.await();

        System.out.println("父线程<InheritableThreadLocal>:" + inheritableThreadLocal.get());
    }
}


结果:



0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics