本文是前文《Java 最多见的 200+ 面试题》的第一个补充模块。html
让咱们天天都有进步,老王带你打造最全的 Java 面试清单,认真把一件事作到极致。java
ThreadLocal 是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象作一个映射,各个线程之间的变量互不干扰,在高并发场景下,能够实现无状态的调用,适用于各个线程不共享变量值的操做。面试
ThreadLocal 原理:每一个线程的内部都维护了一个 ThreadLocalMap,它是一个 Map(key,value)数据格式,key 是一个弱引用,也就是 ThreadLocal 自己,而 value 存的是线程变量的值。算法
也就是说 ThreadLocal 自己并不存储线程的变量值,它只是一个工具,用来维护线程内部的 Map,帮助存和取变量。数组
数据结构,以下图所示:网络
(图片来源于网络)session
与 HashMap 不一样,ThreadLocalMap 结构很是简单,没有 next 引用,也就是说 ThreadLocalMap 中解决 Hash 冲突的方式并不是链表的方式,而是采用线性探测的方式。所谓线性探测,就是根据初始 key 的 hashcode 值肯定元素在 table 数组中的位置,若是发现这个位置上已经被其余的 key 值占用,则利用固定的算法寻找必定步长的下个位置,依次判断,直至找到可以存放的位置。数据结构
源代码实现以下:并发
/
* Increment i modulo len.
*/
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
/
* Decrement i modulo len.
*/
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
复制代码
ThreadLocal 在 ThreadLocalMap 中是以一个弱引用身份被 Entry 中的 Key 引用的,所以若是 ThreadLocal 没有外部强引用来引用它,那么 ThreadLocal 会在下次 JVM 垃圾收集时被回收。这个时候 Entry 中的 key 已经被回收,可是 value 又是一强引用不会被垃圾收集器回收,这样 ThreadLocal 的线程若是一直持续运行,value 就一直得不到回收,这样就会发生内存泄露。高并发
咱们知道 ThreadLocalMap 中的 key 是弱引用,而 value 是强引用才会致使内存泄露的问题,至于为何要这样设计,这样分为两种状况来讨论:
比较以上两种状况,咱们能够发现:因为 ThreadLocalMap 的生命周期跟 Thread 同样长,若是都没有手动删除对应 key,都会致使内存泄漏,可是使用弱引用能够多一层保障,弱引用 ThreadLocal 不会内存泄漏,对应的 value 在下一次 ThreadLocalMap 调用 set、get、remove 的时候被清除,算是最优的解决方案。
ThreadLocal 适用于独立变量副本的状况,好比 Hibernate 的 session 获取场景。
示例代码:
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
public static Session getCurrentSession(){
Session session = threadLocal.get();
try {
if(session ==null&&!session.isOpen()){
//...
}
threadLocal.set(session);
} catch (Exception e) {
// TODO: handle exception
}
return session;
}
复制代码
查看全部面试题:《Java 最多见 200+ 面试题》
扫描下方二维码,关注更多动态:
相关文章推荐: