前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ThreadLocal的plus版--InheritableThreadLocal

ThreadLocal的plus版--InheritableThreadLocal

作者头像
Java进阶之路
发布2022-08-03 17:03:38
2360
发布2022-08-03 17:03:38
举报

一:简述

我们知道ThreadLocal可以实现线程级别下的数据隔离,但是如果需要将当前线程的值传递给子线程,是需要自己去写逻辑实现的,会比较复杂。而InheritableThreadLocal帮助我们解决了这个问题。本篇文章就和大家一起聊聊InheritableThreadLocal。

二:InheritableThreadLocal的原理

1.数据怎么存储

我们可以看到InheritableThreadLocal继承了ThreadLocal,并且重写了ThreadLocal的getMap()以及createMap()方法。getMap()返回Thread类的inheritableThreadLocals成员变量,createMap()方法的作用是创建一个ThreadLocalMap并且赋值给当前线程的inheritableThreadLocals,所以InheritableThreadLocal的get(),set(),remove()方法是继承自ThreadLocal,实现原理和ThreadLocal一样,只不过ThreadLocal数据是存储在Thread的threadLocals成员变量中,而InheritableThreadLocal是存储在Thread的inheritableThreadLocals成员变量中。

代码语言:javascript
复制
public class InheritableThreadLocal<T> extends ThreadLocal<T> {    
    protected T childValue(T parentValue) {        
         return parentValue;
    }    
    // 返回当前线程的inheritableThreadLocals成员变量
    ThreadLocalMap getMap(Thread t) {       
    return t.inheritableThreadLocals;
    }    
    //创建一个ThreadLocalMap 并且赋值给inheritableThreadLocals
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}
代码语言:javascript
复制

注:ThreadLocal原理在我的另外一篇文章讲的很彻底,这里就不再阐述了,原文地址:TheadLocal的实现原理

2.数据是怎么传递给子线程的?

在线程的构造函数中,调动了init()方法,在init()方法中调用createInheritedMap()方法初始化子线程的inheritableThreadLocals,并且将父线程中的inheritableThreadLocals的值取出来赋值给子线程的inheritableThreadLocals。

代码语言:javascript
复制
public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
}

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) {
        ...其他无关源码 一些赋值操作 为了篇幅这里省略了        
        //inheritThreadLocals默认是true 
        //如果需要传递并且父线程的inheritableThreadLocals不为空 
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)        
        // 那么就初始化inheritableThreadLocals并且把父线程的inheritableThreadLocals中的值传递给子线程
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        
                this.stackSize = stackSize;        /* Set thread ID */
        tid = nextThreadID();
    }

接下来我们分析createInheritedMap()方法

createInheritedMap()

createInheritedMap()方法调用了ThreadLocalMap的有参构造函数。

代码语言:javascript
复制
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {        
     return new ThreadLocalMap(parentMap);
}
代码语言:javascript
复制

在构造函数中,遍历了父线程的inheritableThreadLocals,然后遍历父线程inheritableThreadLocals的Entry数组,重新封装成Entry,并且计算数组下标放入到子线程的inheritableThreadLocals中。这也就把数据从父线程传递给了子线程。

代码语言:javascript
复制
private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;            
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];            
            //遍历父线程inheritableThreadLocals的Entry数组
            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];                if (e != null) {                    
                @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();                    
                    //如果key为null 代表是无效数据 不需要传递给子线程
                    if (key != null) {                        
                    //取出父线程的value
                        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++;
                    }
                }
            }
        }
代码语言:javascript
复制

总结:

InheritableThreadLocal的数据是存储在inheritableThreadLocals中的,而Thread在利用构造函数实例化的时候会将父线程的inheritableThreadLocals中的值复制一份给自己,保存在自己的inheritableThreadLocals中,这样就完成了父子线程之间的数据传递。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java进阶之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档