ThreadLocal与InheritableThreadLocal区别

特点

ThreadLocal声明的变量是线程私有的成员变量,每个线程都有该变量的副本,线程对变量的修改对其他线程不可见。

InheritableThreadLocal声明的变量同样是线程私有的,但是子线程可以从父线程继承InheritableThreadLocal声明的变量。

子线程对InheritableThreadLocal变量的修改对父线程是不可见的,同样父线程对InheritableThreadLocal变量的修改对子线程也不可见。

子线程只是在初始化的时候继承父线程的InheritableThreadLocal变量值,初始化以后父线程对InheritableThreadLocal变量的修改对子线程不可见。

示例代码:

public class InheritableThreadLocalApp {

    public static void main(String[] args) {
        final InheritableThreadLocal<String> local1=new InheritableThreadLocal<String>();
        final InheritableThreadLocal<HashMap> local2=new InheritableThreadLocal<HashMap>();

        final HashMap<String,String>  hashMap=new HashMap<>();
        hashMap.put("1","1");

        local1.set("1");
        local2.set(hashMap);

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(2000);
                        System.out.println("2秒以后。。。。。");
                        // 仅仅能访问到 new Thread 之前的数据
                        System.out.println(Thread.currentThread().getName()+"-local1:"+local1.get());

                        local1.set("3");

                        HashMap<String,String> hashMap= local2.get();
                        hashMap.put("3","3");
                        System.out.println(Thread.currentThread().getName()+"-local2:"+local2.get().size());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        local1.set("2");
        hashMap.put("2","2");

        try {
            Thread.sleep(5000);
            System.out.println("5秒以后。。。。。");
            System.out.println(Thread.currentThread().getName()+"-local1:"+local1.get());
            System.out.println(Thread.currentThread().getName()+"-local2:"+local2.get().size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ThreadUtil.waitExit();
    }

}

运行结果

2秒以后。。。。。
Thread-0-local1:1
Thread-0-local2:3
2秒以后。。。。。
Thread-0-local1:3
Thread-0-local2:3
5秒以后。。。。。
main-local1:2
main-local2:3
2秒以后。。。。。
Thread-0-local1:3
Thread-0-local2:3

1) InheritableThreadLocal声明的变量同样是线程私有的,但是子线程可以从父线程继承InheritableThreadLocal声明的变量( local1.get() 获取值为1 说明这点)

2) 父线程无法拿到其子线程修改InheritableThreadLocal变量的值( local1 变量的值在子线程中设置为 3 后,父线程获取的值仍然是 2,这是因为父线程和子线程中local1 存储的已经不是同1个对象了)

3) 子线程对InheritableThreadLocal变量的修改对父线程是不可见的,同样父线程对InheritableThreadLocal变量的修改对子线程也不可见( local1变量的值在子线程中设置为 3 后,父线程获取的值仍然是 2)

4)子线程只是在初始化的时候继承父线程的InheritableThreadLocal变量值,初始化以后父线程对InheritableThreadLocal变量的修改对子线程不可见(见下面源码分析)

Thread 源码分析

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }



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

        this.name = name;

        Thread parent = currentThread();
        
        /***************省略无关代码**************/
       
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            // 子线程初始化时继承父线程的对象
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

        /***************省略无关代码**************/
    }

    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }

ThreadLocal 源码分析

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];  // 子线程继承的对象和父线程是同1个对象
                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++;
                    }
                }
            }
        }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值