美文网首页
ThreadLocal源码分析

ThreadLocal源码分析

作者: HannahLi_9f1c | 来源:发表于2020-04-24 22:28 被阅读0次

    ThreadLocal作用

    ThreadLocal用来存储线程的局部变量,不同线程之间的数据私有化,不能共享。在多线程环境下就不会有线程安全问题。ThreadLocal可以用来存储数据库连接、Session等,达到了线程隔离的目的。

    ThreadLocal的使用

    在不同的线程上进行set(),get()取出的就是在该线程下的值。

      ThreadLocal<String>local = new <String>ThreadLocal();
            local.set("main");
            Thread thread1 = new Thread(){
                @Override
                public void run() {
                    local.set("zhangsan");
                    System.out.println("Thread1"+local.get());
                }
            };
            thread1.start();
            System.out.println("Thread2"+local.get());
    

    ThreadLocal源码分析

    set源码

    从源码看出,set方法先是通过当前线程获取ThreadLocalMap,不为空,则将当前ThreadLocal对象作为key,当前ThreadLocal存储的值作为value存储put进map中。如果map为空,则先创建map,再讲key-value存入。这里的map类似于HashMap的结构

        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
    ThreadLocalMap的结点的结构

    ThreadLocalMap是由Entry构成,结点里key为ThreadLocal对象,并且是一个弱引用,弱引用的对象在JVM垃圾回收的时候,一定会被回收,但是value是强引用。这样会导致即使结点已经不可用了也不会被回收,造成内存泄漏。

    static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
    
    回收key为null的结点

    当调用set(),remove(),get()方法时,内部都会调用expungeStaleEntry(),对key为null的结点进行清除。

      if (k == null) {
                        e.value = null;
                        tab[i] = null;
                        size--;
                    }
    

    线程池的ThreadLocal

    当使用线程池管理线程时,线程时可以复用的,那么要及时remove(),否则会导致业务逻辑上的错误。

    面试题

    ThreadLocal原理
    • ThreadLocal概念:ThreadLoal 变量存储线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。
    • 原理:Thread线程包含ThreadLocalMap指向threadLocals引用,Map存储Entry结点,每个结点由ThreadLocal弱引用和value强引用。通过当前线程获取线程的ThrreadLocalMap,然后再通过Map存取每个线程独有的副本,通过get()方法获取,set()方法赋值。
    每个线程的ThreadLocalMap是什么时候创建的?
    • 在第一次调用set()方法时调用
    扩容算法
    探测性清除

    调用set(),get(),remove()方法时,遇到key为null的过期数据会进行清除,为了防止出现内存泄漏。

    相关文章

      网友评论

          本文标题:ThreadLocal源码分析

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