多线程进阶InheritableThreadLocal

上篇说的是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);
    }
}
public
class 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++;
                    }
                }
            }
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值