ThreadLocal
是一个线程的本地变量, 也就意味着这个变量是线程独有的,是不能与其他线程共享的,它并不是解决多线程共享变量的问题。
所以ThreadLocal
与线程同步机制不同,线程同步机制是多个线程共享同一个变量,而ThreadLocal
是为每一个线程创建一个单独的变量副本,故而每个线程都可以独立地改变自己所拥有的变量副本,而不会影响其他线程所对应的副本。可以说ThreadLocal
为多线程环境下变量问题提供了另外一种解决思路。
ThreadLocal
的思想就是用空间换时间,使各线程都能访问属于自己这一份的变量副本,变量值不互相干扰,减少同一个线程内的多个函数或者组件之间一些公共变量传递的复杂度。
1、ThreadLocalMap
解析
ThreadLocal
内部定义了一个ThreadLocalMap
的内部类,ThreadLocalMap
实际利用Entry
来实现key-value
的存储,如下所示:
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
…
}
ThreadLocalMap
是实现线程隔离机制的关键,从以上代码可以看出Entry
的key
就是ThreadLocal
,而value
就是值。同时,Entry
也继承WeakReference
,所以说Entry
所对应key
(ThreadLocal
实例)的引用为一个弱引用。
我们主要来看下核心的getEntry()
、set(ThreadLocal> key, Object value)
方法
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
private void set(ThreadLocal<?> key, Object value) {
// We don’t use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
// 根据 ThreadLocal 的散列值,查找对应元素在数组中的位置
int i = key.threadLocalHashCode & (len-1);
// 采用“线性探测法”,寻找合适位置
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// 若key 存在,直接覆盖
if (k == key) {
e.value = value;
return;
}
// key == null,但是存在值(因为此处的e != null),说明之前的ThreadLocal对象已经被回收了
if (k == null) {
// 用新元素替换陈旧的元素
replaceStaleEntry(key, value, i);
return;
}
}
//创建新元素
tab[i] = new Entry(key, value);
int sz = ++size;
// 如果没有清理陈旧的 Entry 并且数组中的元素大于了阈值,则进行 rehash
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
2、核心方法解析
(1) get()
返回此线程局部变量的当前线程副本中的值
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的成员变量 threadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// 从当前线程的ThreadLocalMap获取相对应的Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings(“unchecked”)
// 获取目标值
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
最后
分享一些资料给大家,我觉得这些都是很有用的东西,大家也可以跟着来学习,查漏补缺。
《Java高级面试》
《Java高级架构知识》
《算法知识》
最后
分享一些资料给大家,我觉得这些都是很有用的东西,大家也可以跟着来学习,查漏补缺。
《Java高级面试》
[外链图片转存中…(img-QltWF8TG-1714366604945)]
《Java高级架构知识》
[外链图片转存中…(img-TX4sALfo-1714366604946)]
《算法知识》
[外链图片转存中…(img-ypfNY0wu-1714366604947)]