ThreadLocal简单的总结

每个线程都有一个threadLocals对象 其实质是一个链表
链表的每个元素就是一个entry,这个entry的key是WeakReference,value则是我们设置值
所以这就意味着 当我们设置多个threadlocal对象则在thread的threadLocals中就有多个entry。
因为entry的key是弱引用,其会在jvm发生gc(无论是minor ,major,full gc)之后被回收。
内存泄漏
1.比如我们的key 因为gc 被回收 但是value 则永远无法在访问
解决方案:在ThreadLocal的get(),set(),remove()的时候都会清除线程ThreadLocalMap里所有key为null的value。

2.就是我们的线程一直不结束,且也一直不使用上述三个方法的api,或者就算使用了get和set但是一直 没使用remove 而在此期间key也没有回收,这就导致这个内存一值被占用。

Threadlocal

一个threadlocal对象为每一个线程创建一个类似map(其实是数组内部存储一个entry对象,entry的key是弱引用包装的threadlocal value就是我们设置的值)
这个map会赋值给该线程 作为线程的一个属性!因此这边需要注意的是当我们用多个threadlocal操作一个线程 则map里面包含的数据就是多个!

弱引用对象会在threadlocal被jvm gc的时候被回收(没有任何强引用指向threadlocal实例)放入到队列中(如果我没又设置队列则不放入队列)

内存溢出或者内存泄漏的原因
我们这样一般很少会用很多threadlocal对象操作线程,所以一般都是一个threadlocal对应多个线程
那么就相当于每个线程都携带一个map 一个map包含这个弱引用的threadlocal的key和对应value

一般内存异常是指多个线程都没有回收map中的结果进而导致内存溢出,当然也可以理解为内存泄漏
因为在这段时间我们不使用他们 也不删除。这就导致内存一直被占用但是无法释放!

当我们使用的threadlocal不是全局对象 是可以被回收的 那么我们的map中就有可能存在key为null情况这就导致我们无法使用我们value
这才是真正的内存泄漏,而对于上述key不为null还

所以 如果我们定义一个全局变量threadlocal 那么对于单线程 就算我们设置了 不删除 也不会有内存泄漏,但是对于线程池 或者迟迟不结束的线程!
那么我们不删除threadlocal 那么我们下次在使用会覆盖的。
但是我们定义一个局部变量threadlocal 那么对于线程池 或者迟迟不结束的线程! 则有可能存在key是null的内存泄漏数据!
所以我们需要解决这个内存泄漏
而对于set get remove都会删除key=null的entry
但是需要注意的是 其必须遇到key=null时候才会删除,如果我们get的时候就算有key=null的情况 但是没遇上则是不会删除的

key 使用强引用:引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。
key 使用弱引用:引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。
比较两种情况,我们可以发现:由于ThreadLocalMap的生命周期跟Thread一样长,如果都没有手动删除对应key,都会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

你可能感兴趣的:(ThreadLocal简单的总结)