玩转ThreadLocal

ThreadLocal 是啥?  有什么作用?怎么玩? 底层如何实现?

听说过ThreadLocal内存泄漏吗?  为啥?

ThreadLocal key为啥设计成弱引用呢?

三步走玩转ThreadLocal

1.ThreadLocal详解

是啥: ThreadLocal专门为线程服务,为线程提供一个单独的存储数据,对其他线程不可见,目的就是实现线程间资源的隔离。

基本操作:

set() 通过threadLocal向当前线程中存一个线程私有的值 "赵二"

get() 通过threadLocal获取当前线程私有的值

remove() 干掉线程中的当前thraedLocal及值

玩起来:

通过threadLocal,主线程set一个"赵二",AAA线程set一个"张三", BBB线程先set一个"李四" 后set一个"王五"

观察得出结论,

用同一个ThreadLocal  不同的线程set值互不影响,同一个线程set值会覆盖

可以猜测threadLocal这个对象 更像是一个"标识",而不具备存储数据,具体的数据应该是存到了线程当中。

底层实现:

根据表现出来的性质大概也能猜到,每个线程应该会有一个存储threadLocal的地方,根据不同的threadLocal标识能获取到不同数据

答案就在这里,Thread类中的182行,

ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap是ThreadLocal的一个静态内部类

这一看 好家伙 这玩意这么像HashMap

其内部又套娃静态内部类Entry,但是这个Entry继承了弱引用这个之后再说

Entry的key就是ThreadLocal,value就是具体的值,ThreadLocalMap内部存的就是一个Entry数组

画个图就清楚了,

每个线程Thread中有一个ThreadLocalMap

ThreadLocalMap中存的是Entry数组,key为ThreadLocal,value为具体的值

在看看常用方法就更简单了

获取到当前线程的ThreadLocalMap,把<ThreadLocal,value>存进去

获取到当前线程的ThreadLocalMap,找到ThreadLocal对应的Entry,返value

2.听说过ThreadLocal内存泄漏吗?

所谓内存泄漏可以这么理解,有的对象明明没有引用了 不需要了,但是内存中干不掉,造成内存浪费

为啥会这样呢,

举个实例,

线程AAA通过threadLocal  set"张三"到ThreadLocalMap,

等AAA使用完了threadLocal,不需要他了,但是threadLocal并不会被gc回收掉 包括他的value值,

因为threadLocal此时正作为一个Entry的key,被threadLocalMap引用,

而threadLocalMap属于Thread的全局变量,生命周期与Thread相同,

也就是说Thread不销毁,ThreadLocalMap就不会回收,其中的Entry不会回收,Entry不会回收 造成内存泄漏

(这里假设的threadLocal是普通引用,而实际是弱引用下面再说)

OK,那咋整呢,用完ThreadLocal及时把引用它的Entry干掉呗

threadLocal.remove();

或者干脆点 让线程销毁,一切都over

3.弱引用问题

会经常听到有说内存泄漏是因为ThreadLocal是弱引用造成的,

因为ThreadLocal是弱引用, 弱引用任一次GC都会把他回收,那么Entry的key就为null了,Entry就永远访问不到了,造成内存泄漏

我觉得这样说也对也不对,

内存泄漏主要原因是Entry干不掉,因为他被ThreadLocalMap牢牢地把握住了,只能手动把他remove掉,

弱引用的话只是帮忙把Entry的key干掉,而ThreadLocal有一层保护机制,set()或者get()时,如果找出来的key为null,则会帮忙把Entry干掉,帮忙避免一下内存泄漏

so 用完ThreadLocal请及时remove() !

原文地址:https://www.cnblogs.com/ttaall/p/15080595.html