• 学习ThreadLocal实现原理


    ThreadLocal的思想是以空间换时间,而锁的思想是以时间换空间,threadLocal的实现就是讲成员变量的副本拷贝到自己的线程内部,

    因为不同的线程之间是隔离的,所以可以通过这种方式实现线程安全。

    先来看一个示例:

    /**
     * 分析ThreadLocal类的实现原理
     * 我们解决线程安全问题,那么以时间换空间,使用锁机制。要么以空间
     * 换时间,使用threadLocal,隔离线程
     */
    public class AnalysisThreadLocal {
    
        private static ThreadLocal<Map<String, String>> threadLocal = new ThreadLocal<Map<String, String>>() {
            @Override protected Map<String, String> initialValue() {
                return new HashMap<>();
            }
        };
    
        public static void main(String[] args) throws ParseException {
            new Thread(() -> {
                threadLocal.get().put("1", "aaaaa");
                String key = threadLocal.get().get("1");
                System.out.println(Thread.currentThread().getName() + " key: " + key);
            }).start();
    
            new Thread(() -> {
                String key = threadLocal.get().get("1");
                System.out.println(Thread.currentThread().getName() + " key: " + key);
            }).start();
    
        }
    }
    

      

    执行结果:

     线程Thread-0 在自己的副本中put值,然后 在线程Thread-1获取不到。

    get方法:

    /**
    * Returns the value in the current thread's copy of this
    * thread-local variable. If the variable has no value for the
    * current thread, it is first initialized to the value returned
    * by an invocation of the {@link #initialValue} method.
    *
    * @return the current thread's value of this thread-local
    */
    public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null) {
    @SuppressWarnings("unchecked")
    T result = (T)e.value;
    return result;
    }
    }
    return setInitialValue();
    }

    看一下注释:这个方法会返回当前线程的thread-local变量副本,如果当前线程没有副本值,则首先

    调用initialValue方法来初始化这个副本值。

     

    首先到Thread类的成员变量上去取副本值,ThreadLocalMap map = getMap(t);

     如果为null则调用初始化方法:

    T value = initialValue();
    这个方法会调到我们自己的实现类方法,实例化具体需要保证线程安全的变量。

    然后将当前ThreadLocal对象与变量维护到ThreadLocalMap中,然后赋值给当前线程的字段ThreadLocals

    再看一下ThreadLocalMap这个类,传进来的ThreadLocal对象与变量维护到Entry节点上,

     

    完成以上设置,将ThreadLocal与变量封装成一个ThreadLocalMap,然后赋值给Thread的字段后,就把这个变量返回了。

    然后我们可以使用这个变量,示例中我们的变量是一个HashMap,我们向里面put值。

    然后在当前线程再get出来。

    这时候getMap就可以拿到值,ThreadLocalMap

     调用map.getEntry 拿到Entry值,然后在拿到变量的值HashMap,然后就可以根据key找到value值。

    如果这时候另外一个线程也想拿到这个值,

    然后这个线程为重复第一个线程的动作,也会调用初始化方法,拷贝一个副本,将ThreadLocal对象与副本封装成ThreadLocalMap,赋值给

    当前线程的ThreadLocals字段,然后将变量返回,因为是新的HashMap,所以我们那第一个线程设置的key去取值,得到的一定是null。

     

  • 相关阅读:
    opencv-活体检测
    人脸识别
    Opencv-python基本操作
    白话深度学习与Tensorflow(二)
    Linux系统入门(一)-未完成
    编程题29 题目:求对角线元素之和
    编程题28 题目 排序
    编程题27 题目:求100之内的素数
    编程题 18兵乓球比赛
    编程题21 求阶数总和
  • 原文地址:https://www.cnblogs.com/warrior4236/p/12507210.html
Copyright © 2020-2023  润新知