Java

ThreadLocal Thread ThreadLocalMa

2020-09-15  本文已影响0人  马小莫QAQ

前言

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对象来观察数据。

上一篇下一篇

猜你喜欢

热点阅读