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 可以避免在多线程环境中共享数据时出现的线程安全问题,非常适合在多线程编程中使用。

184

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



