ThreadLocal底层原理
1. 简介
在Java中,ThreadLocal是一个非常有用的类,它允许我们在多线程环境中存储和访问线程本地变量。
每个线程都可以独立地更改其ThreadLocal实例的值,而不会影响其他线程的值。
2. 线程的分类
线程分为用户线程和守护线程:
- 用户线程就是普通线程
- 守护线程就是JVM的后台线程
比如垃圾回收线程就是一个守护线程,守护线程会在其他普通线程都停止运行之后自动关闭。我们可以通过设置thread.setDaemon(true)来把一个线程设置为守护线程。
3. 底层原理
ThreadLocal是Java中所提供的线程本地存储机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻、任意方法中获取缓存的数据。
3.1 Thread类中有一个ThreadLocalMap类型的变量
ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal对象)中都存在一个ThreadLocalMap。
Map的key为ThreadLocal对象,Map的value为需要缓存的值。
3.2 ThreadLocalMap是ThreadLocal类的静态内部类
为什么要这样设计呢?
ThreadLocal通过给ThreadLocalMap使用默认的权限修饰符,使得ThreadLocalMap无法被其他包的类引用,最终将ThreadLocalMap完美地隐藏起来,同时ThreadLocal提供了一系列操作容器ThreadLocalMap的方法(get、set等),供外界使用。
3.3 总结
Thread类里面有一个ThreadLocalMap类型的变量,但是外界无法直接操作这个ThreadLocalMap,提供了一个工具箱ThreadLocal帮助我们操作ThreadLocal。
3.4 存在问题
如果在线程池中使用ThreadLocal会造成内存泄漏,因为当ThreadLocal对象使用完之后,应该要把设置的key,value,也就是Entry对象进行回收,但线程池中的线程不会回收,而线程对象是通过强引用指向ThreadLocal对象之后,手动调用ThreadLocal的remove方法,手动清除Entry对象。
3.5 应用场景
ThreadLocal经典的应用场景就是连接管理。
一个线程持有一个连接,该连接对象可以在不同的方法之间进行传递,线程之间不共享同一个连接。
4. 使用方法
Thread类里面都包含了一个Map。然后每一个Map就对应了一个ThreadLocal。
然后这样的话,它每次调用一个ThreadLocal的一个类的话,它就会调用ThreadMap里面的具体的那个ThreadLocal。
这样的话,每个线程都对应自己的一个Local的对象,也是一个Object的东西。
4.1 ThreadLocal中的set方法
获取当前线程,然后获取当前线程中的ThreadLocalMap(即threadLocals变量指向的)。
如果不为空,则把当前对象ThreadLocal作为键,外界传过来的参数作为值,保存ThreadLocalMap中。
如果为空,则创建一个新的ThreadLocalMap。
4.2 ThreadLocal中的get方法
先获取当前线程对象,然后拿到当前线程对象的ThreadLocalMap,在根据键(即当前对象ThreadLocal)找到值。
4.3 ThreadLocalMap中键值
ThreadLocalMap以ThreadLocal作为键,值是我们调用ThreadLocal的set方法传进来的。
4.4 ThreadLocal中的HashMap的键值
在使用ThreadLocal时,我们通常会创建一个静态的ThreadLocal实例,并在需要存储线程本地变量的地方使用它。每个线程都可以它通过ThreadLocal实例来获取和设置线程本地变量的值,而不会影响其他线程。
例如,以下代码片段创建了一个ThreadLocal实例,用于存储线程本地的计数器变量:
private static ThreadLocal<Integer> counter = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue(){
return 0;
}
};
在每个线程中,可以使用以下代码获取和更新计数器变量的值:
int value = counter.get(); // 获取计数器变量的值
counter.set(value + 1); // 更新计数器变量的值
在这里,ThreadLocal的key是当前线程,value是当前线程本地的计数器变量。
5. Thread、ThreadLocal和ThreadLocalMap三者关系
5.1 ThreadLocal的作用
- 工具类,提供一系列方法操作ThreadLocalMap,比如get/set/remove。
- 隔离Thread和ThreadLocalMap,防止程序员直接创建ThreadLocalMap。自身的get/set内部会判断当前线程是否已经绑定一个ThreadLocalMap,有就继续用,没有就为其绑定。
5.2 Thread和ThreadLocalMap的关系
一个Thread只能有一个ThreadLocalMap。
5.3 ThreadLocalMap和ThreadLocal的关系
ThreadLocalMap以ThreadLocal为键存储数据。
参考资料: