Java高并发7-inheritableThreadLocal实现父子线程变量同步原理

一、复习

  • ThreadLocal的set\get等方法

二、threadLocal不具有继承性

package com.ruigege.threadFoundation1;

public class ThreadLocalExtend {

	public static ThreadLocal<String> threadLocal = new ThreadLocal<>();
	
	public static void main(String[] args) {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				threadLocal.set("我是子线程的");
				System.out.println(threadLocal.get());
			}
		});
		
		thread.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(threadLocal.get());
	}	
}

7.1

  • 从上面的两个ThreadLocal实例中可以看出,实例不具有继承性,也就是说主线程和子线程threadLocal变量值是不相等的,这也符合前面源码解析set方法。

二、如何让子线程能够访问到父线程的值呢?

  • 我们还有一个成员变量没讲呢,那就是inheritableThreadLocal
  • 我们先说一个类InheritableThreadLocal,这个类继承字ThreadLocal
public class InheritableThreadLocal<T> extends ThreadLocal<T>{	
	protected T childValue(T parentValue){
		return parentValue;
	}
	ThreadLocalMap getMap(Thread t){
		return t.inheritableThreadLocals;
	}
	
	void createMap(Thread t,T firstValue){
		t.inheritableThreadLocals = new ThreadLocalMap(this,firstValue);//this是一个InheritableThreadLocal实例。
	}
}
  • 后两个方法,可以看出来,其实就是把threadLocals成员变量换成了inheritaleThreadLocals。这样就完成替换了,下面看一下如何完成子线程调用父线程的变量
  • 先来看看Thread源码
public Thread(Runnable target){
	init(null,target,"Thread-"+nextThreadNum(),0);
}

private void init(ThreadGroup g,Runnable target,String name,long stackSize,AccessControlContext acc){
	....
	//获取当前线程(4)
	Thread parent = currentThread();
	....
	//如果父线程的inheritableThreadLocal变量不为null
	if(parent.inheritableThreadLocal != null){
	this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals;
	this.stackSize = stackSize);
	tid = nextThreadID();
}
static ThreadLocalMap createInheritedMap(Thread ThreadLocalMap map){
	return new ThreadLocalMap(map);
}
  • 如上代码在创建线程的时候,在构造函数里面会调用init方法
  • 进入到init方法里面,语句4就是获取了父线程,然后在后面的判断里,先判断一下父线程的inheritableThreadLocals是不是为空,如果不为空,那么我们赋值给子线程里面的inheritableThreadLocals,其中调用了一个函数,其实这个函数就是重新建立了一个ThreadLocalMap实例,接下来我们来观察一下源码

package com.ruigege.threadFoundation1;

public class ThreadLocalMap {
	
	private Entry[] table;
	private T 
	
	private ThreadLocalMap(ThreadLocalMap parentMap) {
		Entry[] parentTable = parentMap.table;
		int len = parentTable.length;
		setThreshole(len);
		table = new Entry[len];
		
		
		for(int j=0;j<len;j++) {
			Entry e = parentTable[j];
			if(e != null) {
				//下面这几行就是为了获取Entry实力的key和value并且生成一个新的Entry实例
				@SuppressWarnings("unchecked")
				ThreadLocal<Object> key = (ThreadLocal<Object>)e.get();
				if(key != null) {
					Object value = key.chirld(e.value);//返回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++;
				}
			}
		}
	}
	
}

  • 这段代码的基本思想就是复制父线程的inheritableThreadLocals变量到子线程中去。

三、并发和并行

  • 并发指的是一段时间内多个线程同时执行,并且没有停止;
  • 并行指的是单位时间内多个线程同时执行,并且没有停止;
  • 并发强调的是一段时间,可能是由多个单位时间内组成的,并且可能一个单位时间只运行了一个线程。

四、源码:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值