马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
什么是ThreadLocal
ThreadLocal是java.lang下面的一个类,是用来办理java多线程程序中并发题目的一种途径;通过为每一个线程创建一份共享变量的副本来保证各个线程之间的变量的访问和修改互相不影响;
ThreadLocal存放的值是线程内共享的,线程间互斥的,重要用于线程内共享一些数据,克制通过参数来通报,如许处理后,可以或许优雅的办理一些现实题目。
比如一次用户的页面操作哀求,我们可以在最开始的filter中,把用户的信息生存在ThreadLocal中,在同一次哀求中,再利用到用户信息,就可以直接到ThreadLocal中获取就可以了。
ThreadLocal有四个方法,分别为:
1.initialValue:返回此线程局部变量的初始值
2.get:返回此线程局部变量的当前线程副本中的值。如果这是线程第一次调用该方法,则创建并初始化此副本。
3.set:将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不必要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。
4.remove:移除此线程局部变量的值。
ThreadLocal的实现原理
ThreadLocal中用于生存线程的独有变量的数据布局是一个内部类:ThreadLocalMap,也是k-v布局。
key就是当前的ThreadLocal对象,而v就是我们想要生存的值。
Thread类对象中维护了ThreadLocalMap成员变量,而ThreadLocalMap维护了以ThreadLocal为key,必要存储的数据为value的Entry数组。这是它们三者之间的基本包含关系,我们必要进一步到源码中探求踪迹。
检察Thread类,内部维护了两个变量,threadLocals和inheritableThreadLocals,它们的默认值是null,它们的类型是ThreadLocal.ThreadLocalMap,也就是ThreadLocal类的一个静态内部类ThreadLocalMap。
在静态内部类ThreadLocalMap维护一个数据布局类型为Entry的数组,节点类型如下代码所示:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
从源码中我们可以看到,Entry布局现实上是继承了一个ThreadLocal类型的弱引用并将其作为key,value为Object类型。这里利用弱引用是否会产生题目,我们这里临时不讨论,在文章结束的时候一起讨论一下,临时可以理解key就是ThreadLocal对象。对于ThreadLocalMap,我们一起来了解一下其内部的变量:
// 默认的数组初始化容量
private static final int INITIAL_CAPACITY = 16;
// Entry数组,巨细必须为2的幂
private Entry[] table;
// 数组内部元素个数
private int size = 0;
// 数组扩容阈值,默以为0,创建了ThreadLocalMap对象后会被重新设置
private int threshold;
这几个变量和HashMap中的变量十分类似,功能也类似。
ThreadLocalMap的构造方法如下所示:
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
// 初始化Entry数组,巨细 16
table = new Entry[INITIAL_CAPACITY];
// 用第一个键的哈希值对初始巨细取模得到索引,和HashMap的位运算代替取模原理一样
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
// 将Entry对象存入数组指定位置
table = new Entry(firstKey, firstValue);
size = 1;
// 初始化扩容阈值,第一次设置为10
setThreshold(INITIAL_CAPACITY);
}
从构造方法的表明中可以了解到,该构造方法是懒加载的,只有当我们创建一个Entry对象并必要放入到Entry数组的时候才会去初始化Entry数组。
每个线程有一个 ThreadLocalMap:
每个线程(Thread)都维护着一个私有的 ThreadLocalMap。这个 ThreadLocalMap 是 Thread 类的一个内部类,它是一个哈希表,用来存储 ThreadLocal 对象及其关联的值。
每个 ThreadLocal 对象是作为 ThreadLocalMap 中的键(Key),而每个键对应的值(Value)则是线程独立的变量副本。
ThreadLocalMap 的筹划:
ThreadLocalMap 是 Thread 类中的一个成员变量。它是一个类似于哈希表的数据布局,此中的每一对键值对表示线程局部变量与其值。
在每个线程开始时,ThreadLocalMap 会为空,只有当线程访问某个 ThreadLocal 变量时,才会创建一个条目。
如果线程访问一个 ThreadLocal 变量而且没有找到对应的值(便是第一次访问),那么 ThreadLocal 会调用 initialValue() 方法来初始化该值。
内存回收:
由于 ThreadLocalMap 是基于弱引用存储 ThreadLocal 键的,意味着当 ThreadLocal 对象被回收时,ThreadLocalMap 会主动清理它对应的值。这防止了 ThreadLocal 键没有被清理时造成内存泄漏。
但是,在利用线程池时,线程会被复用,因此必要显式调用 ThreadLocal.remove() 来清理 ThreadLocalMap 中的值,克制内存泄漏。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |