因为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方法举例,

/*** Returns the value in the current thread's copy of this* thread-local variable.  If the variable has no value for the* current thread, it is first initialized to the value returned* by an invocation of the {@link #initialValue} method.** @return the current thread's value of this thread-local*/public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();}

4.InheritableThreadLocal

Thread类中有两个ThreadLocalMap,一个是threadLocals,一个是inheritableThreadLocals。

threadLocals保存的是当前线程中的ThreadLocal变量们,inheritableThreadLocals保存的是当前线程父线程中的变量们。

InheritableThreadLocal类覆写了getMap和createMap这两个方法,

 /*** Get the map associated with a ThreadLocal.** @param t the current thread*/ThreadLocalMap getMap(Thread t) {return t.inheritableThreadLocals;}
/*** Create the map associated with a ThreadLocal.** @param t the current thread* @param firstValue value for the initial entry of the table.* @param map the map to store.*/void createMap(Thread t, T firstValue) {t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);}

可以看出在初始化或者getMap的时候,获取到的都是inheritableThreadLocals引用,操作的也是inheritableThreadLocals这个ThreadLocalMap。

5.threadLocals和inheritableThreadLocals的初始化

/*** Initializes a Thread.** @param g the Thread group* @param target the object whose run() method gets called* @param name the name of the new Thread* @param stackSize the desired stack size for the new thread, or*        zero to indicate that this parameter is to be ignored.*/private void init(ThreadGroup g, Runnable target, String name,long stackSize) {...Thread parent = currentThread();...if (parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);...}

在new一个Thread的时候会调用Thread的init方法,该方法中如果parent线程的inheritableThreadLocals不是null的话,就会用createInheritedMap方法,用parent的inheritableThreadLocals中的元素构造一个新的ThreadLocalMap。

注意:该操作只在线程初始化的时候进行,所以在该线程初始化之后,parent线程对parent线程自己的inheritableThreadLocals变量的操作不会影响到当前线程的inheritableThreadLocals了,因为已经不是同一个map了。

MDC就是利用这个InheritableThreadLocal把父线程的context带到子线程中,把上下文传递到子线程中通过日志输出,把一次完整的请求串联起来。

6.parent线程

Thread parent = currentThread();

在Thread的init方法中,是通过获得当前线程作为parent线程,也就是说,在哪个线程中new的这个Thread并start的,执行该操作的线程就是new的新Thread的parent线程。

但是init方法只在线程初始化的时候执行一次,所以如果用的线程池来使线程重用的话,就不会再调用这个init方法了,这会带来一些问题,后面会具体说。

log(二)——MDC实现之ThreadLocal相关推荐

  1. log(一)——MDC入门

    1.MDC是什么 先来一段原版注释, /*** This class hides and serves as a substitute for the underlying logging* syst ...

  2. log(五)——MDC总结

    1.为什么最开始子线程会得到父线程MDC设置的内容? 创建子线程的时候会调用init(ThreadGroup g, Runnable target, String name,long stackSiz ...

  3. log(四)——MDC使用

    1.MDC put 用MDC的put方法,把需要的context添加到当前线程的context map中. 之前说过,子线程在创建的时候会把父线程中的inheritableThreadLocals变量 ...

  4. java(spring boot2.x版本)实现二维码生成(可以插入中间log和底部文字)

    1.创建一个spring boot项目(非必须): 项目结构: 2.导入maven依赖: <dependency><groupId>org.springframework.bo ...

  5. 一生挚友redo log、binlog《死磕MySQL系列 二》

    一生挚友redo log.binlog 系列文章 前言 一.redo log 二.如何根据项目情况设置innodb_log_file_size 二.binlog 三.什么是两阶段提交 四.为什么需要两 ...

  6. ThreadLocal类

      一.概述   ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它 ...

  7. 深入研究java.lang.ThreadLocal类

    2019独角兽企业重金招聘Python工程师标准>>> 一.概述 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而 ...

  8. Log4j2的MDC详解

    概述 MDC介绍 MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能.某些应用程序采用多线程的方 ...

  9. tf2.0环境下“module ‘tensorflow‘ has no attribute ‘log‘”的解决办法

    写在这里的初衷,一是备忘,二是希望得到高人指点,三是希望能遇到志同道合的朋友. 目录 一.问题 二.根本原因 三.解决办法 方法一 方法二 一.问题 目前,尝试着通过tensorflow对医学图像进行 ...

最新文章

  1. gff文件_GFF格式说明
  2. 使用php+swoole对client数据实时更新
  3. PTA 03-树1 树的同构 (25分)
  4. 他是学计算机的这个句子中宾语是动词性的,现代汉语语法部分练习,带答案
  5. Java生鲜电商平台-高并发核心技术订单与库存实战
  6. 风湿病年鉴 | scRNA-seq研究揭示骨关节炎患者的半月板退变新机制
  7. 书评:使用Scikit-Learn和TensorFlow进行动手机器学习
  8. koa操作mongodb,封装mongdb操作方法
  9. r语言保存成html文件,R语言统计结果输出至本地文件的几种方法示例
  10. python定时任务启动与停止_对Python定时任务的启动和停止方法详解
  11. 开启线程的几种方式、实现 Runnable 接口、实现 Runnable 接口、继承 Thread 类、FutureTask 配合 Thread
  12. windows 7系统的无损分区软件
  13. 基于Java毕业设计中国古诗词学习平台源码+系统+mysql+lw文档+部署软件
  14. 适合苹果4s的微信版本_6.1.3装上微信了,新手看这里
  15. windows server 2012 更改网络位置
  16. liunx基础知识篇 偏指令
  17. vue cli 脚手架 重新安装步骤
  18. python能制作ppt动画效果吗_那些超酷的视频效果,真的是用PPT动画做的吗?
  19. 中国老百姓一生要交多少税?
  20. python3收邮件_认真对待 Python3 收邮件

热门文章

  1. C++如何限制模板类的类型
  2. xp怎么让计算机开启ftp,Win7和WinXP共享打印机和FTP怎么设置
  3. JZOJ 1403.渡河
  4. 发表SCI或EI类英文文章的投稿经验
  5. 【12月原创】RT-thread - 柿饼UI ——范进中举
  6. php获取笔顺矢量,笔顺生成器在线-笔顺生成器php版源码下载-西西软件下载
  7. 海贝思蓝牙接收器Linux,特定场景使用测评,电视民工的海备思蓝牙X2发射接收器使用心得。...
  8. 王 第潜艇三天 引用类型 继承
  9. Bomblab(ICS课程回课pku)
  10. 访问者模式的java语言_Java 设计模式系列(二三)访问者模式(Vistor)