ThreadLocal源码分析

2020-04-24  本文已影响0人  HannahLi_9f1c

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原理
每个线程的ThreadLocalMap是什么时候创建的?
扩容算法
探测性清除

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

上一篇下一篇

猜你喜欢

热点阅读