文章目录
- 1.ThreadLocal是什么?
- 2.ThreadLocald实现原理&源码解析
- 3.ThreadLocal-内存泄露问题
1.ThreadLocal是什么?
ThreadLocal 是 Java 中的一个线程局部变量类
。它提供了一种在多线程环境
下,为每个线程独立存储数据的机制。
并且:
ThreadLocal 通过为每个线程创建一个独立的副本
来实现线程隔离
。每个线程都可以独立地修改和访问自己的副本
,而不会影响其他线程的副本。每个线程都可以像访问普通变量
一样访问 ThreadLocal 对象
,而不必担心线程安全问题。
2.ThreadLocald实现原理&源码解析
ThreadLocal本质来说就是一个·线程内部存储类·,从而让多个线程只操作自己内部的值
,从而实现线程数据隔离
基本方法有:
- set(value) 设置值
- get() 获取值
- remove() 清除值
set(value) 设置值
首先获取当前线程,然后获取当前线程的 ThreadLocalMap 对象。如果 ThreadLocalMap 存在
,就将当前 ThreadLocal 对象
作为键
,将值 value
存储到其中;否则,创建一个新的 ThreadLocalMap
,并将当前 ThreadLocal 对象和值 value 存储到其中。
/**
* 设置线程局部变量的值。
* @param value 要设置的值
*/
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的 ThreadLocalMap,用于存储线程局部变量
ThreadLocalMap map = getMap(t);
if (map != null)
// 如果 ThreadLocalMap 存在,则将当前 ThreadLocal 对象作为键,将 value 作为值存储起来
map.set(this, value);
else
// 如果 ThreadLocalMap 不存在,则创建一个新的 ThreadLocalMap,并将当前 ThreadLocal 对象和 value 存储到其中
createMap(t, value);
}
get() 获取值
通过ThreadLocal 对象去取对应的value
首先,获取当前线程并获取其对应的 ThreadLocalMap 对象。如果 ThreadLocalMap 存在,则通过调用 getEntry(this) 方法
获取当前 ThreadLocal 对象
对应的条目。如果条目存在,则返回条目中存储的值
。如果线程局部变量不存在
,则调用 setInitialValue() 方法返回初始值。
/**
* 获取线程局部变量的值。
* @return 线程局部变量的值,如果不存在则返回初始值
*/
public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的 ThreadLocalMap,用于存储线程局部变量
ThreadLocalMap map = getMap(t);
if (map != null) {
// 通过 ThreadLocalMap 获取对应的条目
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
// 如果条目存在,则返回条目中存储的值
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
// 如果线程局部变量不存在,则返回初始值
return setInitialValue();
}
remove() 清除值
根据ThreadLocal 删除对
/**
* 从当前线程的 ThreadLocalMap 中移除当前 ThreadLocal 对象对应的条目。
*/
public void remove() {
// 获取当前线程的 ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null) {
// 如果 ThreadLocalMap 存在,则调用 remove(this) 方法移除当前 ThreadLocal 对象对应的条目
m.remove(this);
}
}
3.ThreadLocal-内存泄露问题
什么是内存泄漏:
内存泄漏是指在程序中,不再使用
的对象仍然被占用着内存
,无法
被垃圾回收器回收
释放,导致内存占用
逐渐增加
,最终可能导致内存耗尽
或性能下降。
Java对象中的四种引用类型:强引用
、软引用
、弱引用
、虚引用
强引用:最为普通的引用方式,表示一个对象处于有用且必须的状态
,如果一个对象具有强引用,则GC并不会回收
它。即便堆中内存不足了,宁可出现OOM,也不会对其进行回收
弱引用:表示一个对象处于可能有用且非必须的状态
。在GC线程扫描内存区域时,一旦发现弱引用,就会回收到弱引用相关联的对象。对于弱引用的回收,无关内存区域是否足够,一旦发现则会被回收
出现内存泄漏的原因:
-
长期持有:如果在 ThreadLocal 中设置的值
长时间持有
,而没有进行及时清理和释放
,可能导致内存泄漏
。(只要线程不结束,就一直存在) -
线程结束不清理:如果在
线程结束
时没有
正确地清理 ThreadLocal
,可能会导致内存泄漏。因为线程结束后,对应的ThreadLocalMap 对象不会被垃圾回收
,其中的ThreadLocal 对象
也无法释放。
-
对象强引用:每一个
Thread维护一个ThreadLocalMap
,在ThreadLocalMap中的Entry对象继承了WeakReference
。其中key为使用弱引用
的ThreadLocal实例,value为线程变量的副本
解决办法就是:使用完ThreadLocal后主动 remove 释放 key,value