ThreadLocal原理分析

来源:互联网 发布:淘宝货款没到 编辑:程序博客网 时间:2024/05/20 14:18

ThreadLocal是什么?

ThreadLocal就是指线程局部变量,就是指多个线程并发运行的时候,使用ThreadLocal装饰的变量在每个线程里都是单独使用的。

好处

由于每个线程拥有了自己的变量,所以消除了多线程情况下的竞争关系。

实现原理

要理解ThreadLocal的实现原理,那还是得从源码出发

    public void set(T value) {        Thread t = Thread.currentThread(); // 获取当前线程        ThreadLocalMap map = getMap(t);  // 获取一个map        if (map != null)            map.set(this, value);        else            createMap(t, value);    }    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();    }

由上面的代码可知,设置和获取值得时候都会获取到一个ThreadLocalMap,并且用ThreadLocal作为key,真正需要使用的值作为value

ThreadLocal.ThreadLocalMap threadLocals = null; // 当前线程的map

接下来还需要关注ThreadLocalMap对象的存储方式

    static class Entry extends WeakReference<ThreadLocal<?>> {            /** The value associated with this ThreadLocal. */            Object value;            Entry(ThreadLocal<?> k, Object v) {                super(k);                value = v;            }        }

从Entry可以很明细的知道,在map中的key是一个弱引用,当key在没有强引用的时候,gc的时候key就会被回收掉,也就是当ThreadLocal变量设置为null的时候就会被回收

为什么key设置为弱引用?

首先假设key不是弱引用,而是强引用,当ThreadLocal变量设置为null的时候,由于map中还存在强引用,那么ThreadLocal变量在线程没结束就永远不会被gc回收掉。那么这样就会出现内存泄漏的问题。

所以为了避免ThreadLocal设置为null的时候不会因为map引用而导致内存泄漏的问题,所以key就必须用弱引用。

ThreadLocal为什么会出现内存泄漏?

从源码分析可知道,value值是强引用的,当ThreadLocal变量设置为null的时候,key被回收了,但value还没被回收,而且由于key为null而导致value永远不可达,虽然ThreadLocalMap中的set(),get(),remove()这些方法引用的时候,会将key为null,value不为null的清除掉。但假设ThreadLocal变量设置为null的时候,长时间没调用过以上的3个方法,并且线程长时间存在,这时候就会导致value内存泄漏了。

怎么避免ThreadLocal的内存泄漏?

每次使用完ThreadLocal之后都调用一下remove()方法,清除数据,这样就可以避免内存泄漏问题了。

原创粉丝点击