父子间的枢纽-InheritableThreadLocal

本文基本jdk1.8。
日常开发中可以用ThreadLocal保存本线程的专属数据。但是要进行并行操作时,如果将父线程数据传递给后续的子线程呢?
答案是InheritableThreadLocal。

1.InheritableThreadLocal

InheritableThreadLocal源码比较简单,继承自ThreadLocal,不了解的可以参考之前ThreadLocal的解析

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
  
    protected T childValue(T parentValue) {
        return parentValue;
    }

    ThreadLocalMap getMap(Thread t) {
    	// 这里也是调整为获取 inheritableThreadLocals而不是threadLocals 
       return t.inheritableThreadLocals;
    }

	
    void createMap(Thread t, T firstValue) {
    // 覆盖了ThreadLocal的createMap方法,区别在于ThreadLocal赋值给了t.threadLocals 
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

整个类主要采用inheritableThreadLocals替代 threadLocals ,但这里看着一定一头雾水,凭啥换了参数就实现了线程参数传递。
那具体的传递过程在哪里呢?
答案在Thread里。

2. Thread

实际化一个Thread

Thread thread = new Thread();

进入构造方法,一路递进到init方法。

 	 public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
	
	private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        ... 
        // InheritableThreadLocal 时存在这个参数
        if (parent.inheritableThreadLocals != null)
        	// 子线程执行赋值父线程的数据
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        ...
    }
    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];
                if (e != null) {
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                     // 过滤那些失效的ThreadLocal
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        // 重新计算索引
                        int h = key.threadLocalHashCode & (len - 1);
                        // TheadLocal采用拉链存储,hash相同则后移至下一个null的位置
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }

3.遗留问题

InheritableThreadLocal 虽然解决了父子线程参数传递问题,但是实际开发时,线程都是从线程池中获取的,这就导致了并不一定每次线程都要进行初始化操作,线程的数据存在缓存问题。
当然解决方式也有,阿里提供的方案是transmittable

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值