在 Android 和 Java 中,ThreadLocal
的实现原理主要依赖于 ThreadLocalMap
类。以下是 ThreadLocal
的实现细节和原理:
1. ThreadLocal 类
ThreadLocal
是一个用于存储线程局部变量的类。它的关键方法包括 get
、set
和 remove
,这些方法在底层操作一个与当前线程相关联的 ThreadLocalMap
实例。
2. ThreadLocalMap 类
ThreadLocalMap
是 Thread
类的内部类,实际上是一个哈希表,用于存储每个线程的线程局部变量。它的结构和方法如下:
2.1 内部结构
- Entry 类:
ThreadLocalMap
的内部类Entry
是一个键值对的容器。键是ThreadLocal
对象(使用弱引用),值是线程局部变量的值。
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
}
- table:
ThreadLocalMap
使用一个Entry
数组来存储键值对。
2.2 设置和获取值
- set 方法:通过计算
ThreadLocal
对象的哈希码并将其映射到table
数组中的索引位置,将值存储到Entry
中。如果在该位置已经有Entry
对象,并且其ThreadLocal
键与当前的ThreadLocal
相同,则更新值;否则,创建新的Entry
对象。
void set(ThreadLocal<?> key, Object value) {
// 计算索引
int i = key.threadLocalHashCode & (table.length - 1);
// 遍历 table 中的 Entry
for (Entry e = table[i]; e != null; e = table[nextIndex(i, table.length)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
// 如果没有找到对应的 Entry,则创建新的 Entry
table[i] = new Entry(key, value);
}
- get 方法:计算
ThreadLocal
对象的哈希码并找到对应的Entry
。如果找到匹配的Entry
,则返回其值;否则,返回null
。
Object get(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
for (Entry e = table[i]; e != null; e = table[nextIndex(i, table.length)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
return e.value;
}
if (k == null) {
expungeStaleEntries();
}
}
return null;
}
2.3 内存管理
-
弱引用:
ThreadLocal
的键(ThreadLocal
对象)使用弱引用,确保当ThreadLocal
对象不再被引用时,可以被垃圾回收,从而避免内存泄漏。 -
清理过时的条目:
ThreadLocalMap
会定期清理已回收的ThreadLocal
对象对应的Entry
。在get
方法中,如果发现键已为null
,则会调用expungeStaleEntries
方法来移除过时的条目。
3. ThreadLocal 的生命周期
- ThreadLocal 变量的创建:每个线程创建时会初始化一个
ThreadLocalMap
对象来存储其线程局部变量。 - 线程结束:当线程结束时,其
ThreadLocalMap
也会被垃圾回收。由于ThreadLocal
的键是弱引用,当ThreadLocal
对象不再被使用时,它也会被回收,从而避免内存泄漏。
总结
ThreadLocal
的实现原理主要依赖于 ThreadLocalMap
,它使用 ThreadLocal
对象作为键,并通过弱引用来避免内存泄漏。每个线程都有自己的 ThreadLocalMap
实例,确保线程局部变量的隔离。ThreadLocal
提供了线程安全的方式来管理每个线程的独立数据,避免了线程间的同步问题。