用法
ThreadLocal<T> 是带了一个泛型 T 的,意思就是不同线程从同一个 ThreadLocal 实例中会取出属于自己的 T 类型的实例(这些实例在不同线程中是不同的)。
因此,ThreadLocal 适用于每个线程需要有一个自己独立的 T 类型实例变量,也就是说,变量需要在线程间隔离,但是在方法或类间共享的场景。
我们看 ThreadLocal 的注释中给我们示例了比较典型的用法:
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
public static int get() {
return threadId.get();
}
}
一个 ThreadLocal 类型的静态变量 threadId,不同的线程通过调用 ThreadId.get 方法时所访问的 threadId 变量,都是独属于线程自己的 threadId 变量(既不同的实例)。
原理
其实 ThreadLocal 中,它的原理精髓在于内部类 ThreadLocalMap。在 ThreadLocalMap 中还有个内部类 Entry:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
Entry 是一个 WeakReference,它所持有的弱引用就是 ThreadLocal 实例。同时它还有一个类变量 value,也就是 ThreadLocal 所对应的值。
内部类中还有一个成员变量 table,它是一个 Entry 数组。我们上面说了,Entry 其实就是 ThreadLocal 的弱引用,而且每个线程 Thread 都有一个 ThreadLocalMap 类型的成员变量 threadLocals。因此,线程的 threadLocals 的 table,就是包含了属于该线程的所有 ThreadLocal 变量的数组集合。
ThreadLocal.get 方法
通过 ThreadLocal.get 方法,我们就能一窥 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();
}
当线程调用 get 方法时,通过 getMap(t) 方法能够取出该线程所持有的 ThreadLocalMap 类型的成员变量 Thread.threadLocals,也就是上面代码中的 map。注意,这个 map 就已经是每个线程自己所独有的了。通过 map.getEntry(this) 可以从这个 ThreadLocalMap 的 table 中取出该 ThreadLocal 实例所对应的 Entry e,最后通过 e.value 来取出该 ThreadLocal 所对应的值。











网友评论