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


    一、复习

    • ThreadLocal的setget等方法

    二、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变量到子线程中去。

    三、并发和并行

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

    四、源码:

  • 相关阅读:
    pycharm上传代码到码云(详细)
    我是如何理解ThreadLocal
    前两次成绩汇总
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    第一次作业
    单例模式之懒汉式与饿汉式
    浅谈对srping框架的理解
  • 原文地址:https://www.cnblogs.com/ruigege0000/p/13967160.html
Copyright © 2020-2023  润新知