1 什么是 ThreadLocal
说 ThreadLocal 之前要先说 Thread,每启动一个线程就会有一个对应的线程管理 Thread 对象,这个Thread对象可以调用currentThread()方法获取,
这个Thread 对象有一个容器 叫 threadLocals 类型是ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals = null;//存放K V值 (threadlocal引用,value)
这个 threadLocals 容器存放的是一个 K V 值
K 是 threadlocal 对象引用 / this
v 是 存放的数据
每个线程对象都有一个对应的容器,这样就实现了多个线程的数据隔离
2 这和 ThreadLocal 有什么关系,
Threadlocal 的 get()方法和 set()方法其实就是拿到 Thread 对象的这个 KV 容器 threadLocals 进行操作
set方法源码
public void set(T value) {
Thread t = Thread.currentThread();//获取关联的线程对象Thread
ThreadLocalMap map = getMap(t);//拿到Thread对象里管理的threadLocals容器
if (map != null) {//第一次添加threadLocals为null
map.set(this, value);//放入Kv值 (threadlocal引用,存放的数据)
} else {
createMap(t, value);//初始化Thread对象的threadLocals容器并放入value数据
}
}
ThreadLocalMap threadLocals 大致的一个存放数据的结构 (这个类在 threadlocal 里,是一个静态内部类)
get方法源码
public T get() {
Thread t = Thread.currentThread(); //获取关联的线程对象Thread
ThreadLocalMap map = getMap(t); //拿到Thread对象里管理的threadLocals容器
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //根据threadlocal对象获取到table数组存放的Entry
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;//取出entry的value
return result;
}
}
3 为什么不直接操作 Thread 的threadLocals,而是要通过 Threadlocal 操作
- 封装性:
ThreadLocal
类为threadLocals
属性提供了更高层次的封装。通过ThreadLocal
的get()
和set()
方法,可以更方便地访问和修改线程局部变量,而无需直接操作Thread
对象。这种封装提高了代码的可读性和可维护性。 - 安全性:直接操作
threadLocals
可能会破坏ThreadLocal
的内部机制,导致数据不一致或线程安全问题。ThreadLocal
类内部对threadLocals
的访问进行了严格的控制,以确保线程隔离性和数据安全性。 ThreadLocal
通过为每个线程创建一个独立的变量副本来实现线程隔离。这个副本是存储在Thread
对象的threadLocals
属性中的,但ThreadLocal
类提供了更方便的方法来访问和操作这些副本。直接操作threadLocals
可能会绕过ThreadLocal
的初始化、清理等机制,导致数据泄漏或不一致。