多线程进阶InheritableThreadLocal

来源:互联网 发布:淘宝双11后生意不好 编辑:程序博客网 时间:2024/04/30 00:58

上篇说的是ThreadLocal,如果对ThreadLocal足够了解的话,InheritableThreadLocal也很好理解。InheritableThreadLocal类继承于ThreadLocal类,所以它具有ThreadLocal类的特性,但又是一种特殊的ThreadLocal,其特殊性在于InheritableThreadLocal变量值会自动传递给所有子线程,而普通ThreadLocal变量不行,那么子线程是否可以修改InheritableThreadLocal变量值然后反向传递给主线程了,答案是对于引用类型来说,其内部的属性改变是可以传递给主线程的,对于基本数据类型以及String,Integer等包装类型来说是不可以的,原因是子线程的变量来源于父线程变量的浅拷贝,首先来个例子:

package com.lzzl.thread10;public class Person {    private String name;    private int id;    @Override    public String toString() {        return "Person [name=" + name + ", id=" + id + "]";    }    public Person(){    }    public Person(String name, int id) {        super();        this.name = name;        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }}
package com.lzzl.thread10;public class MyThreadLocal extends ThreadLocal<Person>{    @Override    protected Person initialValue() {        // TODO Auto-generated method stub        return new Person("初始值",0);    }}package com.lzzl.thread10;public class MyInheritableThreadLocal extends InheritableThreadLocal<Person>{    @Override    protected Person initialValue() {        // TODO Auto-generated method stub        return new Person("in初始值",0);    }}package com.lzzl.thread10;public class Tools {    public static MyThreadLocal t1 = new MyThreadLocal();    public static MyInheritableThreadLocal t2 = new MyInheritableThreadLocal();}
package com.lzzl.thread10;public class Run {        public static void main(String[] args) {            Tools.t2.set(new Person("inmain",1));//执行步骤1            new Thread(new Runnable() {                   public void run() {                    System.out.println("线程A获t2得的值"+Tools.t2.get());//执行步骤4                    Tools.t2.get().setName("---main");//执行步骤5,这里修改了存入的变量的属性                    System.out.println("线程A修改t2的值");//执行步骤6                    System.out.println("线程A获得t2的值"+Tools.t2.get());//执行步骤7                }            },"A").start();            System.out.println("main线程获得t2的值"+Tools.t2.get());//执行步骤2            try {                Thread.sleep(3000);//执行步骤3            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            System.out.println("main线程获得t2的值"+Tools.t2.get());        }}

输出
线程A获t2得的值Person [name=inmain, id=1]
线程A修改t2的值
main线程获得t2的值Person [name=inmain, id=1]
线程A获得t2的值Person [name=—main, id=1]
main线程获得t2的值Person [name=—main, id=1]

到这里已经看出的子线程修改变量的属性反映到了主线程之中

来看看其原理吧,贴上源代码

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.     * @param map the map to store.     */    void createMap(Thread t, T firstValue) {        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);    }}
publicclass Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals = null;ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;public Thread() {        init(null, null, "Thread-" + nextThreadNum(), 0);    } private void init(ThreadGroup g, Runnable target, String name,                      long stackSize) {        if (name == null) {            throw new NullPointerException("name cannot be null");        }        Thread parent = currentThread();//parent为当前线程        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();        this.name = name.toCharArray();        if (security == null || isCCLOverridden(parent.getClass()))            this.contextClassLoader = parent.getContextClassLoader();        else            this.contextClassLoader = parent.contextClassLoader;        this.inheritedAccessControlContext = AccessController.getContext();        this.target = target;        setPriority(priority);        if (parent.inheritableThreadLocals != null)//拷贝父线程的inheritableThreadLocals            this.inheritableThreadLocals =                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        /* Stash the specified stack size in case the VM cares */        this.stackSize = stackSize;        /* Set thread ID */        tid = nextThreadID();    }static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {        return new ThreadLocalMap(parentMap);    }     static class ThreadLocalMap {        static class Entry extends WeakReference<ThreadLocal> {            /** The value associated with this ThreadLocal. */            Object value;            Entry(ThreadLocal k, Object v) {                super(k);                value = v;            }        }        private ThreadLocalMap(ThreadLocalMap parentMap) {//拷贝父线程中的map            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++;                    }                }            }        }    }}
原创粉丝点击