ThreadLocal
的实现涉及到 Java 内部的许多细节,主要依赖于每个线程维护的一个 ThreadLocalMap
对象。以下是 ThreadLocal
实现的关键部分:
1. ThreadLocal
类
ThreadLocal
类本身提供了一些公共方法,如 get()
、set()
和 remove()
,这些方法实际上是对 ThreadLocalMap
进行操作。
public class ThreadLocal<T> {
// 初始化 ThreadLocal 值
protected T initialValue() {
return null;
}
// 获取当前线程的 ThreadLocal 值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T) e.value;
return result;
}
}
return setInitialValue();
}
// 设置当前线程的 ThreadLocal 值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// 移除当前线程的 ThreadLocal 值
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
// 初始化值并放入 ThreadLocalMap
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
// 获取当前线程的 ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
// 创建 ThreadLocalMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// 内部类 ThreadLocalMap
static class ThreadLocalMap {
// ...
// 定义 Entry
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
// 存储 Entry 的数组
private Entry[] table;
// 初始化
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);
}
// 获取 Entry
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) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
// 移除 Entry
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}
// 其他方法...
}
}
2. Thread
类中的 ThreadLocalMap
每个线程都有一个 ThreadLocalMap
,这个 ThreadLocalMap
是 Thread
类中的一个成员变量,用于存储该线程的 ThreadLocal
变量。
public class Thread implements Runnable {
// 每个线程都持有一个 ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals = null;
// 其他线程相关方法和属性...
}
3. ThreadLocalMap
实现
ThreadLocalMap
是 ThreadLocal
类的一个静态内部类,用于存储线程局部变量。它使用 ThreadLocal
的 hashCode
作为键,将值存储在一个 Entry
数组中。Entry
继承自 WeakReference
,使用弱引用来防止内存泄漏。
- 弱引用:
ThreadLocalMap
中的Entry
使用弱引用来引用ThreadLocal
实例,避免内存泄漏。当一个ThreadLocal
实例不再被其他强引用引用时,GC 可以回收它,而不需要显式地移除Entry
。
4. 哈希算法和冲突解决
ThreadLocalMap
使用哈希算法将 ThreadLocal
实例的 hashCode
映射到 Entry
数组的索引位置。如果发生哈希冲突,则使用线性探测法解决冲突。
5. 内存管理
ThreadLocalMap
使用 WeakReference
以及定期清理过期条目来管理内存。通过这些机制,可以防止内存泄漏,即使线程长期存在,已经不再使用的 ThreadLocal
变量也可以被 GC 回收。
总结
ThreadLocal
通过每个线程维护一个独立的 ThreadLocalMap
,并使用弱引用来管理线程局部变量,从而提供线程安全的变量存储。它在多线程编程中非常有用,尤其是在需要确保线程独立性的场景中。