ThreadLocal :每个线程通过此对象都会返回各自的值,互不干扰,这是因为每个线程都存着自己的一份副本。需要注意的是线程结束后,它所保存的所有副本都将进行垃圾回收(除非存在对这些副本的其他引用)

ThreadLocalget操作是这样执行的:ThreadLocalMap map = thread.threadLocals -> return map.getEntry(threadLocal)

ThreadLocalset操作是这样执行的:ThreadLocalMap map = thread.threadLocals -> map.set(threadLocal, value)

三者的关系是:

  • 每个Thread对应的所有ThreadLocal副本都存放在ThreadLocalMap对象中,keyThreadLocalvalue是副本数据
  • ThreadLocalMap对象存放在Thread对象中
  • 通过ThreadLocal获取副本数据时,实际是通过访问Thread来获取ThreadLocalMap,再通过ThreadLocalMap获取副本数据

示例代码如下:

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors; /**
* @author: lihui
* @date: 2020-06-01
*/
public class ThreadLocalStudy { private static final ThreadLocal<String> threadLocal1 = new ThreadLocal<>();
private static final ThreadLocal<String> threadLocal2 = new ThreadLocal<>(); private static CountDownLatch countDownLatch1 = new CountDownLatch(2);
private static CountDownLatch countDownLatch2 = new CountDownLatch(1); public static void main(String[] args)
throws NoSuchFieldException, IllegalAccessException, InterruptedException {
Thread thread1 = new Thread(() -> {
threadLocal1.set("thread1-local1");
threadLocal2.set("thread1-local2");
countDownLatch1.countDown();
try {
countDownLatch2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}); Thread thread2 = new Thread(() -> {
threadLocal1.set("thread2-local1");
threadLocal2.set("thread2-local2");
countDownLatch1.countDown();
try {
countDownLatch2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}); thread1.start();
thread2.start();
countDownLatch1.await(); System.out.println(threadLocal1 + " " + threadLocal2);
printThreadLocalMapInfo(thread1);
printThreadLocalMapInfo(thread2);
countDownLatch2.countDown();
} /**
* 输出相关信息
*/
private static void printThreadLocalMapInfo(Thread thread) throws NoSuchFieldException, IllegalAccessException {
System.out.println("=====" + thread.getName() + "=====");
Object threadLocalMapObject = getThreadLocalMapObject(thread);
System.out.println(threadLocalMapObject);
List<Object> objects = getEntryList(threadLocalMapObject);
for (Object object : objects) {
System.out.println(getEntryKey(object) + " " + getEntryValue(object));
}
} /**
* 获取ThreadLocalMap对象
*/
private static Object getThreadLocalMapObject(Thread thread) throws NoSuchFieldException, IllegalAccessException {
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
return threadLocalsField.get(thread);
} /**
* 获取ThreadLocalMap对象中的所有Entry
*/
private static List<Object> getEntryList(Object threadLocalMapObject)
throws NoSuchFieldException, IllegalAccessException {
Field tableField = threadLocalMapObject.getClass().getDeclaredField("table");
tableField.setAccessible(true);
Object[] objects = (Object[]) tableField.get(threadLocalMapObject);
return Arrays.stream(objects).filter((obj) -> {
return obj != null;
}).collect(Collectors.toList());
} /**
* 获取Entry的key
*/
private static Object getEntryKey(Object entry) throws NoSuchFieldException, IllegalAccessException {
Field referentField = entry.getClass().getSuperclass().getSuperclass().getDeclaredField("referent");
referentField.setAccessible(true);
return referentField.get(entry);
} /**
* 获取Entry的value
*/
private static Object getEntryValue(Object entry) throws NoSuchFieldException, IllegalAccessException {
Field valueField = entry.getClass().getDeclaredField("value");
valueField.setAccessible(true);
return valueField.get(entry);
}
}

输出结果为:

java.lang.ThreadLocal@31221be2 java.lang.ThreadLocal@377dca04
=====Thread-0=====
java.lang.ThreadLocal$ThreadLocalMap@728938a9
java.lang.ThreadLocal@377dca04 thread1-local2
java.lang.ThreadLocal@31221be2 thread1-local1
=====Thread-1=====
java.lang.ThreadLocal$ThreadLocalMap@25f38edc
java.lang.ThreadLocal@377dca04 thread2-local2
java.lang.ThreadLocal@31221be2 thread2-local1
可以看出:Thread类里面的ThreadLocalMap存储着所有ThreadLocal的副本数据。
没有通过ThreadLocal的get方式进行获取数据,而是通过实实在在的通过ThreadLocalMap对象来观察数据。

Java8 API

ThreadLocal Thread ThreadLocalMap 之间的关系的更多相关文章

  1. ThreadLocal和ThreadLocalMap源码分析

    目录 ThreadLocal和ThreadLocalMap源码分析 背景分析 定义 例子 源码分析 ThreadLocalMap源码分析 ThreadLocal源码分析 执行流程总结 源码分析总结 T ...

  2. ThreadLocal与ThreadLocalMap源码分析

    ThreadLocal类 该类主要用于不同线程存储自己的线程本地变量.本文先通过一个示例简单介绍该类的使用方法,然后从ThreadLocal类的初始化.存储结构.增删数据和hash值计算等几个方面,分 ...

  3. 正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)

    Looper 和Handler 是理解好AsyncTask的一个基础,我们可以先从这里开始,先给出一个主线程和子线程互相通信的例子. package com.example.loopertest; i ...

  4. Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系

    转载请包含网址:http://blog.csdn.net/pathuang68/article/details/7351317 一.Surface Surface就是“表面”的意思.在SDK的文档中, ...

  5. (转)C#/.NET主线程与子线程之间的关系

    一般 一个应用程序就对应一个进程,一个进程可有一个或多个线程,而一般有一个主线程.       有的博客上说“至少一个主线程”,这一说法持有怀疑         主线程与子线程之间的关系        ...

  6. [转]C#综合揭秘——细说进程、应用程序域与上下文之间的关系

    引言 本文主要是介绍进程(Process).应用程序域(AppDomain)..NET上下文(Context)的概念与操作.虽然在一般的开发当中这三者并不常用,但熟悉三者的关系,深入了解其作用,对提高 ...

  7. java中paint repaint update 之间的关系

    最近总结了一下java中的paint,repaint和updata三者之间的关系,首先咱们都知道用paint方法来绘图,用repaint重绘,用update来写双缓冲.但是他们之间是怎么来调用的呢,咱 ...

  8. [C#参考]细说进程、应用程序域与上下文之间的关系

    原文转载链接:http://www.cnblogs.com/leslies2/archive/2012/03/06/2379235.html Written by:风尘浪子 引言 本文主要是介绍进程( ...

  9. C#综合揭秘——细说进程、应用程序域与上下文之间的关系

    引言 本文主要是介绍进程(Process).应用程序域(AppDomain)..NET上下文(Context)的概念与操作.虽然在一般的开发当中这三者并不常用,但熟悉三者的关系,深入了解其作用,对提高 ...

随机推荐

  1. TP5整合的导出Excel中没有图片和包含图片两种方法

    之前做了个项目需要导出Excel文件 ,我在网上查了许多资料,最后终于搞定了 ,现在把代码贴到下面 先导入库文件:将文件phpoffice放在根目录的vendor下.获取文件点击:链接:https:/ ...

  2. 今天玩一下python得邮件解析吧,查看邮件内容小儿科,我们下载邮件的附件

    直男,直接上代码. 自己看打印的内容 主要功能如下: #如果邮件内容存在链接则返回链接,若不存在则直接下载邮件附件 import imapclient,re import pyzmail #提取邮件里 ...

  3. NetCore项目实战篇06---服务注册与发现之consul

    至此,我们的解决方案中新建了三个项目,网关(Zhengwei.Gateway).认证中心(Zhengwei.Identity)和用户资源API(Zhengwei.Use.Api).当要访问用户API的 ...

  4. 暴力破解-HTTP Basic认证

    0x01 HTTP Basic认证介绍 基本认证 basic authentication ← HTTP1.0提出的认证方法 基本认证步骤: 1. 客户端访问一个受http基本认证保护的资源. 2. ...

  5. input输入框直接拉起九宫格数字键盘

    <input type="number" pattern="\d*">

  6. 【Leetcode】164. Maximum Gap 【基数排序】

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  7. 【雕爷学编程】Arduino动手做(57)---四档矩形波模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  8. EOS基础全家桶(十二)智能合约IDE-VSCode

    简介 上一篇我们介绍了EOS的专用IDE工具EOS Studio,该工具的优势是简单,易上手,但是灵活性低,且对系统资源开销大,依赖多,容易出现功能异常.那么我们开发人员最容易使用的,可能还是深度定制 ...

  9. router-link传参

    果然还好是一小部分一小部分记录的好. <router-link :to="info">中:to特性可以是路径str,也可以是一个对象形式str. 当info是对象时可以 ...

  10. MYSQL LOCK IN SHARE MODE&FOR UPDATE

    SELECT ... LOCK IN SHARE MODE sets a shared mode lock on the rows read. A shared mode lock enables o ...