用法
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
所对应的值。
网友评论