一、复习

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

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

  • 我们还有一个成员变量没讲呢,那就是inheritableThreadLocal
  • 我们先说一个类InheritableThreadLocal,这个类继承字ThreadLocal
public class InheritableThreadLocal<Textends 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变量到子线程中去。

三、并发和并行

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

四、源码:

posted on 2020-11-13 00:13  心悦君兮君不知-睿  阅读(362)  评论(0编辑  收藏  举报