美文网首页Java
ThreadLocal Thread ThreadLocalMa

ThreadLocal Thread ThreadLocalMa

作者: 马小莫QAQ | 来源:发表于2020-09-15 17:11 被阅读0次

前言

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

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

三者的关系是:

每个Thread对应的所有ThreadLocal副本都存放在ThreadLocalMap对象中,key是ThreadLocal,value是副本数据

ThreadLocalMap对象存放在Thread对象中

通过ThreadLocal获取副本数据时,实际是通过访问Thread来获取ThreadLocalMap,再通过ThreadLocalMap获取副本数据

示例代码如下:

importjava.lang.reflect.Field;

importjava.util.Arrays;

importjava.util.List;

importjava.util.concurrent.CountDownLatch;

importjava.util.stream.Collectors;

/**

* @author: lihui

* @date: 2020-06-01

*/

publicclassThreadLocalStudy {

privatestaticfinal ThreadLocal threadLocal1 =newThreadLocal<>();

privatestaticfinal ThreadLocal threadLocal2 =newThreadLocal<>();

privatestaticCountDownLatch countDownLatch1 =newCountDownLatch(2);

privatestaticCountDownLatch countDownLatch2 =newCountDownLatch(1);

publicstaticvoidmain(String[] args)

throws NoSuchFieldException, IllegalAccessException, InterruptedException {        Thread thread1 =newThread(() -> {

threadLocal1.set("thread1-local1");

threadLocal2.set("thread1-local2");

countDownLatch1.countDown();try{

countDownLatch2.await();            }catch(InterruptedException e) {

e.printStackTrace();            }        });        Thread thread2 =newThread(() -> {

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();    }/**

    * 输出相关信息

    */

privatestaticvoidprintThreadLocalMapInfo(Thread thread) throws NoSuchFieldException, IllegalAccessException {

System.out.println("====="+ thread.getName() +"=====");

ObjectthreadLocalMapObject = getThreadLocalMapObject(thread);

System.out.println(threadLocalMapObject);        List objects = getEntryList(threadLocalMapObject);

for(Objectobject : objects) {

System.out.println(getEntryKey(object) +" "+ getEntryValue(object));

}    }/**

    * 获取ThreadLocalMap对象

    */

privatestaticObjectgetThreadLocalMapObject(Thread thread) throws NoSuchFieldException, IllegalAccessException {

Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");

threadLocalsField.setAccessible(true);

returnthreadLocalsField.get(thread);

}/**

    * 获取ThreadLocalMap对象中的所有Entry

    */

privatestaticList getEntryList(ObjectthreadLocalMapObject)

throws NoSuchFieldException, IllegalAccessException {        Field tableField = threadLocalMapObject.getClass().getDeclaredField("table");

tableField.setAccessible(true);

Object[] objects = (Object[]) tableField.get(threadLocalMapObject);

returnArrays.stream(objects).filter((obj) -> {

returnobj !=null;

}).collect(Collectors.toList());    }/**

    * 获取Entry的key

    */

privatestaticObjectgetEntryKey(Objectentry) throws NoSuchFieldException, IllegalAccessException {

Field referentField = entry.getClass().getSuperclass().getSuperclass().getDeclaredField("referent");

referentField.setAccessible(true);

returnreferentField.get(entry);

}/**

    * 获取Entry的value

    */

privatestaticObjectgetEntryValue(Objectentry) throws NoSuchFieldException, IllegalAccessException {

Field valueField = entry.getClass().getDeclaredField("value");

valueField.setAccessible(true);

returnvalueField.get(entry);

}}

输出结果为:

java.lang.ThreadLocal@31221be2 java.lang.ThreadLocal@377dca04

=====Thread-0=====

java.lang.ThreadLocal$ThreadLocalMap@728938a9java.lang.ThreadLocal@377dca04 thread1-local2java.lang.ThreadLocal@31221be2 thread1-local1=====Thread-1=====

java.lang.ThreadLocal$ThreadLocalMap@25f38edcjava.lang.ThreadLocal@377dca04 thread2-local2java.lang.ThreadLocal@31221be2 thread2-local1

可以看出:Thread类里面的ThreadLocalMap存储着所有ThreadLocal的副本数据。

没有通过ThreadLocal的get方式进行获取数据,而是通过实实在在的通过ThreadLocalMap对象来观察数据。

相关文章

  • Thread、ThreadLocal、ThreadLocalMa

    1 先上一张经典的关系图,完了贴下原始的代码。 纯看代码写的真是挺绕的,先来张图有个整体的印象吧。 对着Thre...

  • ThreadLocal Thread ThreadLocalMa

    前言 ThreadLocal :每个线程通过此对象都会返回各自的值,互不干扰,这是因为每个线程都存着自己的一份副本...

  • ThreadLocal的正确使用与原理

    ThreadLocal是什么 ThreadLocal是线程Thread中属性threadLocals即Thread...

  • ThreadLocal

    ThreadLocal是为了解决线程间数据共享带来的问题 看下Thread, ThreadLocal和Thread...

  • ThreadLocal

    ThreadLocal使用场景 ThreadLocal是绑定在Thread上的变量,生命周期与Thread相同。通...

  • ThreadLocal

    ThreadLocal 是什么?ThreadLocal并不是一个Thread,而它是Thread的局部变量,可以在...

  • ThreadLocal

    理解ThreadLocal 理解ThreadLocal的关键在于理解 Thread, threadLocals, ...

  • juc之五: ThreadLocal

    1. ThreadLocal (JDK版本) 1.1 ThreadLocal 概述 1.2 Thread-Thre...

  • ThreadLocal

    回顾方式 看源码RequestContext->ThreadLocal->Thread->ThreadLocal....

  • 从ThreadLocal到TransmittableThread

    ThreadLocal JDK Description: 我们可以得知ThreadLocal的作用是:Thread...

网友评论

    本文标题:ThreadLocal Thread ThreadLocalMa

    本文链接:https://www.haomeiwen.com/subject/eyvfyktx.html