美文网首页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对象来观察数据。

    相关文章

      网友评论

        本文标题:ThreadLocal Thread ThreadLocalMa

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