ThreadLocal
是 Android 和 Java 中的一种机制,用于在同一线程的多个操作之间存储和获取线程专属的数据。每个线程都有自己的局部变量副本,其他线程无法访问或修改这些变量。这对于需要在同一线程中保持独立状态的场景非常有用,如数据库连接或用户会话信息。
ThreadLocal
的工作原理
ThreadLocal
的原理可以从以下几个方面来理解:
-
每个线程有一个 ThreadLocalMap:
每个线程内部有一个ThreadLocalMap
对象,这个ThreadLocalMap
负责存储所有的ThreadLocal
变量。ThreadLocal
本身不存储值,而是通过ThreadLocalMap
关联值。 -
ThreadLocalMap 的结构:
ThreadLocalMap
是Thread
类的内部类,实际上是一个自定义的哈希表。它的键是ThreadLocal
对象,值是ThreadLocal
存储的变量。 -
设置和获取值:
当你调用ThreadLocal
的set
方法时,它会获取当前线程的ThreadLocalMap
,然后在这个映射中存储键值对(ThreadLocal
和其对应的值)。当你调用get
方法时,它会从当前线程的ThreadLocalMap
中获取与当前ThreadLocal
相关联的值。
代码示例
以下是一个简单的示例,展示了如何使用 ThreadLocal
:
public class ThreadLocalExample {
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
System.out.println("Thread 1 initial value: " + threadLocal.get());
threadLocal.set(100);
System.out.println("Thread 1 new value: " + threadLocal.get());
});
Thread thread2 = new Thread(() -> {
System.out.println("Thread 2 initial value: " + threadLocal.get());
threadLocal.set(200);
System.out.println("Thread 2 new value: " + threadLocal.get());
});
thread1.start();
thread2.start();
}
}
深入理解 ThreadLocal
的实现
-
ThreadLocal 类:
ThreadLocal
类的主要方法有get
、set
和remove
。其中,get
方法用于获取当前线程的值,set
方法用于设置当前线程的值,remove
方法用于删除当前线程的值。 -
ThreadLocalMap 类:
ThreadLocalMap
是一个内部类,类似于哈希表,存储着Entry
对象。Entry
对象的键是ThreadLocal
的弱引用,值是线程局部变量。 -
弱引用(WeakReference):
ThreadLocal
的键是弱引用,目的是防止内存泄漏。如果线程结束并且没有强引用指向ThreadLocal
,ThreadLocal
将会被垃圾回收,从而避免内存泄漏。
ThreadLocal
详细实现
public class ThreadLocal<T> {
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
private void set(ThreadLocal<?> key, Object value) {
int i = key.threadLocalHashCode & (table.length - 1);
for (Entry e = table[i]; e != null; e = table[nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
table[i] = new Entry(key, value);
}
private Object get(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
for (Entry e = table[i]; e != null; e = table[nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
return e.value;
}
if (k == null) {
expungeStaleEntry(i);
}
}
return null;
}
}
}
小结
ThreadLocal
提供了一种方便的方式来存储线程局部变量,每个线程都有自己独立的副本,互不干扰。它的底层实现依赖于 ThreadLocalMap
,利用弱引用防止内存泄漏。使用 ThreadLocal
可以避免在多线程环境中共享数据时出现的线程安全问题,非常适合在多线程编程中使用。