zoukankan      html  css  js  c++  java
  • 学习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。

     

  • 相关阅读:
    12_2 数据分析工具包。
    11_29
    11_28 mongoDB与scrapy框架
    11_28,selenium定位元素,cookies获取
    11_26爬虫find与findall
    day_93_11_25爬虫一requests,项目框架
    11_14flask的启动和orm,反向生成model
    11_13Local与偏函数
    11_12 路由与正则
    day83_11_1 阿里配python使用。
  • 原文地址:https://www.cnblogs.com/warrior4236/p/12507210.html
Copyright © 2011-2022 走看看