zoukankan      html  css  js  c++  java
  • ThreadLocal Thread ThreadLocalMap 之间的关系

    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

  • 相关阅读:
    浅谈Semaphore类
    Python浅谈requests三方库
    191104
    191103
    191102
    191101
    191031
    191030
    191029
    191028
  • 原文地址:https://www.cnblogs.com/eaglelihh/p/13027154.html
Copyright © 2011-2022 走看看