ThreadLocal原理详解
ThreadLocal就像线程的“专属保险箱”,每个线程都有自己的存储空间,互不干扰。想让多个线程同时操作同一个变量?static变量来帮忙!但要是希望每个线程有自己的“私房钱”,就得靠ThreadLocal了。
比如,银行的每个柜台都有一个专门的窗口,只处理自己的客户,ThreadLocal就相当于每个窗口的专属抽屉,其他人进不来。
不过,你得注意这个“保险箱”可不是免费的午餐,用完得记得清理,不然内存可要吃不消了!想知道怎么正确使用它,避免内存泄漏?我下次告诉你。
对了,想不想知道哪些框架也在用这个“黑科技”?下次聊!
1.概述
我们知道,想要实现变量共享,可以采取定义static修饰的类变量(静态变量)的形式,所有的线程共享这个变量。但是现在,我们想要实现每个线程独享这个变量,应该怎么实现呢?
2.什么是ThreadLocal
于是乎,ThreadLocal
出现了。它实现了线程与线程之间的数据的隔离,互不干扰。那么ThreadLocal
到底是何方神圣呢?
ThreadLocal是用来管理线程的私有数据,使得线程对该数据的操作对其他线程不可见,达到数据隔离的效果。
那么,Java中是怎么实现这种机制的呢?接下来一一揭晓。
2.1 Thread、ThreadLocal、ThreadLocalMap三剑客
ThreadLocal
中定义了内部类ThreadLocalMap
,ThreadLocalMap
类似于HashMap
,其中key
为ThreadLocal
,value
为想要存储的值。然后呢,每个Thread
对象中维护了一个ThreadLocalMap
,因此,每个线程都可以很方便的访问只属于自己的数据。
我们通过源代码来跟踪一下Thread、ThreadLocal、ThreadLocalMap三者之间的联系。
ThreadLocal.java
// ThreadLocal.java
public class ThreadLocal {// 静态内部类static class ThreadLocalMap {}
}
Thread.java
// Thread.java
public class Thread {ThreadLocal.ThreadLocalMap threadLocals = null;
}
那么,它们三者的关系呢就像下面这张图一样:
- 人(Thread):当前线程对象。
- 公文包(ThreadLocalMap):属于当前线程对象,用于存放只能由当前线程访问的数据。
- 文件(ThreadLocal):文件的key为ThreadLocal对象
再来看看它们的数据结构:
3.ThreadLocal的作用
先来体验一下ThreadLocal
的API:
public class ThreadLocalTest {private static ThreadLocal<String> threadLocal = new ThreadLocal<>();public static void main(String[] args) {System.out.println(threadLocal.get());threadLocal.set("one and only");System.out.println(threadLocal.get());}
}
接下来我们来验证一下数据隔离的效果。
import lombok.SneakyThrows;import java.util.concurrent.TimeUnit;public class ThreadLocalTest {private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();@SneakyThrowspublic static void main(String[] args) {Thread threadA = new Thread(() -> {threadLocal.set(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName() + "完成了签名")