zoukankan      html  css  js  c++  java
  • ThreadLocal MDC

    因为MDC底层是用ThreadLocal实现的,所以这里补充一些和ThreadLocal相关的知识点。

    1.ThreadLocal的三个层次

    关于ThreadLocal有三个层次,可以按照这三个层次去理解就不会乱。

    三个层次
     * 第一层是Thread空间,通过Thread.currentThread()获得。
     * 第二层是Thread中的两个ThreadLocalMap,threadLocals和inheritableThreadLocals,访问thread对应的两个ThreadLocalMap成员变量获得。
     * 第三层是每个ThreadLocalMap中key——ThreadLocal和value——ThreadLocal的set方法set的值,在get方法中用ThreadLocal的this作为ThreadLocalMap的key获取value。
     * 无论什么操作都要按照这三个层次依次进行才不会乱

    2.ThreadLocalMap

    保存了当前Thread中存放的ThreadLocal和ThreadLocal对应的值的键值对。
    当前线程的所有ThreadLocal变量组成了这个map的keyset,对应的值组成了这个map的valueset。

    3.ThreadLocal的操作

    第一步都是先用Thread.currentThread()获得当前线程,然后getMap获取线程中的ThreadLocalMap。
    像getMap这些操作方法都是包可见性的,包外部无法操作。以ThreadLocal的get方法举例,
    [java] view plain copy
     
    1. /** 
    2.      * Returns the value in the current thread's copy of this 
    3.      * thread-local variable.  If the variable has no value for the 
    4.      * current thread, it is first initialized to the value returned 
    5.      * by an invocation of the {@link #initialValue} method. 
    6.      * 
    7.      * @return the current thread's value of this thread-local 
    8.      */  
    9.     public T get() {  
    10.         Thread t = Thread.currentThread();  
    11.         ThreadLocalMap map = getMap(t);  
    12.         if (map != null) {  
    13.             ThreadLocalMap.Entry e = map.getEntry(this);  
    14.             if (e != null)  
    15.                 return (T)e.value;  
    16.         }  
    17.         return setInitialValue();  
    18.     }  
    [java] view plain copy
     
    1. /** 
    2.      * Returns the value in the current thread's copy of this 
    3.      * thread-local variable.  If the variable has no value for the 
    4.      * current thread, it is first initialized to the value returned 
    5.      * by an invocation of the {@link #initialValue} method. 
    6.      * 
    7.      * @return the current thread's value of this thread-local 
    8.      */  
    9.     public T get() {  
    10.         Thread t = Thread.currentThread();  
    11.         ThreadLocalMap map = getMap(t);  
    12.         if (map != null) {  
    13.             ThreadLocalMap.Entry e = map.getEntry(this);  
    14.             if (e != null)  
    15.                 return (T)e.value;  
    16.         }  
    17.         return setInitialValue();  
    18.     }  

    4.InheritableThreadLocal

    Thread类中有两个ThreadLocalMap,一个是threadLocals,一个是inheritableThreadLocals。
    threadLocals保存的是当前线程中的ThreadLocal变量们,inheritableThreadLocals保存的是当前线程父线程中的变量们。
    InheritableThreadLocal类覆写了getMap和createMap这两个方法,
    [java] view plain copy
     
    1. /** 
    2.     * Get the map associated with a ThreadLocal. 
    3.     * 
    4.     * @param t the current thread 
    5.     */  
    6.    ThreadLocalMap getMap(Thread t) {  
    7.       return t.inheritableThreadLocals;  
    8.    }  
    [java] view plain copy
     
    1. /** 
    2.     * Get the map associated with a ThreadLocal. 
    3.     * 
    4.     * @param t the current thread 
    5.     */  
    6.    ThreadLocalMap getMap(Thread t) {  
    7.       return t.inheritableThreadLocals;  
    8.    }  
    [java] view plain copy
     
    1. /** 
    2.      * Create the map associated with a ThreadLocal. 
    3.      * 
    4.      * @param t the current thread 
    5.      * @param firstValue value for the initial entry of the table. 
    6.      * @param map the map to store. 
    7.      */  
    8.     void createMap(Thread t, T firstValue) {  
    9.         t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);  
    10.     }  
    [java] view plain copy
     
    1. /** 
    2.      * Create the map associated with a ThreadLocal. 
    3.      * 
    4.      * @param t the current thread 
    5.      * @param firstValue value for the initial entry of the table. 
    6.      * @param map the map to store. 
    7.      */  
    8.     void createMap(Thread t, T firstValue) {  
    9.         t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);  
    10.     }  
    可以看出在初始化或者getMap的时候,获取到的都是inheritableThreadLocals引用,操作的也是inheritableThreadLocals这个ThreadLocalMap。

    5.threadLocals和inheritableThreadLocals的初始化

    [java] view plain copy
     
    1. /** 
    2.      * Initializes a Thread. 
    3.      * 
    4.      * @param g the Thread group 
    5.      * @param target the object whose run() method gets called 
    6.      * @param name the name of the new Thread 
    7.      * @param stackSize the desired stack size for the new thread, or 
    8.      *        zero to indicate that this parameter is to be ignored. 
    9.      */  
    10.     private void init(ThreadGroup g, Runnable target, String name,  
    11.                       long stackSize) {  
    12.         ...  
    13.         Thread parent = currentThread();  
    14.         ...  
    15.         if (parent.inheritableThreadLocals != null)  
    16.             this.inheritableThreadLocals =  
    17.                 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);  
    18.         ...  
    19.     }  
    [java] view plain copy
     
    1. /** 
    2.      * Initializes a Thread. 
    3.      * 
    4.      * @param g the Thread group 
    5.      * @param target the object whose run() method gets called 
    6.      * @param name the name of the new Thread 
    7.      * @param stackSize the desired stack size for the new thread, or 
    8.      *        zero to indicate that this parameter is to be ignored. 
    9.      */  
    10.     private void init(ThreadGroup g, Runnable target, String name,  
    11.                       long stackSize) {  
    12.         ...  
    13.         Thread parent = currentThread();  
    14.         ...  
    15.         if (parent.inheritableThreadLocals != null)  
    16.             this.inheritableThreadLocals =  
    17.                 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);  
    18.         ...  
    19.     }  
    在new一个Thread的时候会调用Thread的init方法,该方法中如果parent线程的inheritableThreadLocals不是null的话,就会用createInheritedMap方法,用parent的inheritableThreadLocals中的元素构造一个新的ThreadLocalMap。
    注意:该操作只在线程初始化的时候进行,所以在该线程初始化之后,parent线程对parent线程自己的inheritableThreadLocals变量的操作不会影响到当前线程的inheritableThreadLocals了,因为已经不是同一个map了。
    MDC就是利用这个InheritableThreadLocal把父线程的context带到子线程中,把上下文传递到子线程中通过日志输出,把一次完整的请求串联起来。

    6.parent线程

    [java] view plain copy
     
    1. Thread parent = currentThread();  
    [java] view plain copy
     
    1. Thread parent = currentThread();  
    在Thread的init方法中,是通过获得当前线程作为parent线程,也就是说,在哪个线程中new的这个Thread并start的,执行该操作的线程就是new的新Thread的parent线程。
    但是init方法只在线程初始化的时候执行一次,所以如果用的线程池来使线程重用的话,就不会再调用这个init方法了,这会带来一些问题,后面会具体说。
  • 相关阅读:
    联想 thinkpad 双系统 linux
    日期差值 1096
    np.newaxis用法详解
    Tensorflow InternalError: Blas SGEMM launch failed
    [转载] xmapp启动Tomcat时报JDK、JRE未安装错误的解决方法
    opensuse 装机总结
    opensuse nvidia 解决方案 [转载]
    驱动调试方法
    模块加载——modprobe和insmod的区别(转)
    UBOOT2016.05 看门狗
  • 原文地址:https://www.cnblogs.com/diegodu/p/8953863.html
Copyright © 2011-2022 走看看