一、ThreadLocal核心原理
1. 底层数据结构
// 每个线程持有独立的ThreadLocalMap
class Thread {
ThreadLocal.ThreadLocalMap threadLocals; // 延迟初始化
}
// 自定义哈希表实现(开放寻址法)
class ThreadLocalMap {
Entry[] table;
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value; // 实际存储的值
}
}
2. 关键操作机制
| 方法 | 时间复杂度 | 实现要点 |
|---|---|---|
| set() | O(1)~O(n) | 哈希冲突时线性探测 |
| get() | O(1)~O(n) | 自动清理过期Entry |
| remove() | O(1) | 触发惰性清理 |
内存管理特性:
-
Key(ThreadLocal对象)使用弱引用,避免内存泄漏
-
Value使用强引用,需手动remove避免泄漏
二、在Looper中的经典应用
1. Looper存储实现
// Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed)); // 绑定当前线程
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get(); // 获取当前线程Looper
}
2. 线程隔离保证
graph LR
Thread1-->|ThreadLocalMap|Looper1
Thread2-->|ThreadLocalMap|Looper2
Thread3-->|ThreadLocalMap|null
三、设计优势分析
1. 线程单例模式
-
保证每个线程最多只有一个Looper实例
-
避免使用同步锁(无竞争条件)
2. 高效访问
-
相比HashMap减少哈希计算开销
-
无锁设计提升并发性能
3. 内存安全
// 典型泄漏场景
void leakExample() {
ThreadLocal<Bitmap> local = new ThreadLocal<>();
local.set(bitmap);
// 忘记remove时:
// 1. ThreadLocal弱引用被回收
// 2. Value强引用持续存在
}
四、深度应答技巧
追问:"为什么不用同步的全局Map存储Looper?"
架构师级回答:
-
性能考量:"全局Map需要同步锁,而ThreadLocal无锁访问,在Handler高频场景下性能差异显著(实测吞吐量提升5倍)"
-
GC友好性:"ThreadLocalMap随线程销毁自动清理,而全局Map需要维护复杂的生命周期"
-
架构整洁:"符合线程封闭原则,避免交叉污染"
实现细节补充:
"在Android 9之后,Looper的ThreadLocal实现加入了优化:
-
使用快速路径(firstGet)避免多次哈希查找
-
Entry数组扩容策略改为2的幂次方
-
添加清除过期Entry的启发式算法"
关联知识扩展:
"这种设计模式也应用于:
-
Glide的RequestManagerRetriever
-
ARouter的Interceptor体系
-
OkHttp的ConnectionPool线程绑定"
504

被折叠的 条评论
为什么被折叠?



