学 无 止 境 , 与 君 共 勉 。java
ThreadLocal
是一个线程内部的变量,只在本线程中使用,隔离其余线程ThreadLocal
内部维护了一个ThreadLocalMap
Thread
内部引用了ThreadLocalMap
ThreadLocalMap
能够保存
键值对,可是一个ThreadLocal
只能保存一个值,而且各个线程数据互不干扰ThreadLocalMap
存储时的key
永远为当前的ThreadLocal
ThreadLocalMap
存储时的key
是弱引用的每一个ThreadLocal
只能存储一个数据,若是须要存储多个值的话,能够定义多个ThreadLocal
。ThreadLocal
在内部维护了一个ThreadLocalMap
用来存储这些值。web
ThreadLocalMap
并无去实现Map
接口,它定义了一个Entry
数组,每一个Entry
以<key,value>
的形式来保存值,其中key
为当前ThreadLocal
自己,value
为要保存的值。数组
注意
Entry
继承了WeakReference
,它的key
是弱引用的,会被垃圾回收掉,因此会存在key
为null
的状况安全
ThreadLocalMap
提供了三个方法:微信
ThreadLocal
为key
存放值ThreadLocal
为key
获取存放的值Thread.currentThread()
ThreadLocalMap
ThreadLocalMap
是否存在createMap
,初始化一个ThreadLocalMap
,并赋值ThreadLocal
做为key
,进行插入操做:
Thread.currentThread()
ThreadLocalMap
ThreadLocalMap
是否存在setInitialValue
进行初始化,并返回null
;ThreadLocal
做为key
获取值:
清理当前ThreadLocal
对应的Entry
对象。并调用清理重置方法。app
ThreadLocalMap
并无实现Map
接口,它不是经过链表的形式去避免Hash冲突的,而是经过后移的方式去实现。set方法时,若是当前要存放的位置的key
和要设置的key
不一致,则会对下一个位置进行判断,直到找到key
相同或者为null
或者Entry
为null
的位置。工具
在实际的项目中,咱们的线程通常都是由线程池来管理的,线程会一直存在,ThreadLocalMap
的value就有可能得不到回收,发送内存泄漏。为了处理这一问题,ThreadLocal
的get()、set()方法都有可能会清除key
为null
的Entry
对象。安全起见,当咱们使用完后应该手动调用remove()
方法清理掉数据。spa
某些数据好比用户ID,极可能在整条业务线上多个方法中都须要用到,若是经过方法参数的形式一层一层的传递下去,总体代码显得凌乱不优雅,这时能够经过ThreadLocal
的方式存储。一般能够经过AOP或者拦截器的方式进行赋值,执行完业务逻辑以后调用remove()
方法。线程
private final static ThreadLocal<UserInfo> TL_USER = new ThreadLocal<>();
TL_USER.set(userInfo);
UserInfo userInfo = TL_USER.get();
TL_USER.remove();
复制代码
在实际项目中咱们一般会将时间相关的方法写在一个工具类中,每每会用到SimpleDateFormat
进行格式化,它是线程不安全的。能够经过ThreadLocal来实现独享对象code
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
复制代码
创做不易,若是各位以为有帮助,求点赞 支持
微信公众号: 俞大仙