ThreadLocal源码解读及内存泄漏

ThreadLocal

ThreadLocal是什么?

从名字可以看出ThreadLocal叫做线程本地,即ThreadLocal中填充的变量是属于当前线程的,该变量对其它线程而言是隔离的

源码分析一下ThreadLocal的作用

ThreadLocal<M> tl = new ThreadLocal<>();
tl.set(new M());
tl.remove();

点进去set()方法看一下:

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

获取当前线程,然后将ThreadLocal作为key,你设置的值作为value,放到了一个ThreadLocalMap中.

我们再看一下createMap()方法:

很简单,就是new了一个ThreadLoaclMap

void createMap(Thread t, T firstValue) {
     
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

再看一下getMap()方法:

注意,getMap()方法是在Thread类当中,维护了ThreadLocalMap变量ThreadLocal.ThreadLocalMap threadLocals = null;

即每一个线程内部都有一个ThreadLocalMap变量,当你使用threadLocal.set(value)方法时,其实是以ThreadLocal作为key,你设置的值作为value放置在线程内部的ThreadLocalMap中,所以不同线程间的ThreadLocal是隔离的

ThreadLocalMap getMap(Thread t) {
     
    return t.threadLocals;
}

我们再看一下ThreadLocalMap类

ThreadLocal源码解读及内存泄漏_第1张图片

Entry类继承了WeakReference类.那么Entry为什么要继承WeakReference弱引用呢?

对于ThreadLocal tl = new ThreadLocal<>();而言,如果Entry不使用弱引用而使用强引用,那么当我把tl=null时,GC依然无法回收ThreadLocal对象,因为再ThreadLocalMap中的Entry依然存在一个引用指向了ThreadLocal,造成对象无法回收,存在内存泄漏.所以需要将Entry设置为弱引用.但是还是存在内存泄漏的问题.因为key是弱引用被回收变成了null,但是value依然存在且无法被回收,所以当threadlocal不再使用时,一定要调用threadLocal.remove()方法

ThreadLocal源码解读及内存泄漏_第2张图片

你可能感兴趣的:(内存泄漏,java)