ThreadLocal 是 JDK 提供的用于实现线程封闭的工具类。
我们可以实例项目应用一下:在 context 包下创建一个工具类(如 BaseContext),在其中静态实例化 ThreadLocal,并封装 set、get 和 remove 方法供全局调用。
注:像这种new对象的方式来创建ThreadLocal 其是没有默认值的
原理: 当请求进入时,拦截器解析 Token 获取用户 ID,并通过 set 方法将其绑定到当前执行线程上。
当请求结束时,必须调用 remove 方法清除数据。这样做有两个核心目的:
1 防止数据串扰:避免线程复用时,后续请求读到前一个用户的敏感信息
2 防止内存泄漏:确保在线程池长期运行的环境下,废弃的对象能被 GC 及时回收。
而ThreadLocal 的值保存在ThreadLocalMap这样的结构中,这种结构是一个非常类似与HashMap的结构,他以ThreadLocal作为KEY,value就是ThreadLocal的值每个线程都有一个ThreadLocalMap对象。
如下:
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
private int size = 0;
private int threshold; // Default to 0
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}