这个类提供了线程变量,这不同于其他的变量,它能在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的。
使用示例:
public static void main(String[] args) {
ThreadLocal<String> str = new ThreadLocal<String>();
str.set("hello word");
System.out.println(str.get());
}
接下来我们来看看ThreadLocal的源码。
protected T initialValue() {
return null;
}
类中的protected方法,一般用于我们给Thread变量赋初始值。
其中有个静态内部类ThreadLocalMap,其中的数据结构如下
static class Entry extends WeakReference<ThreadLocal> {
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
此map的key中ThreadLocal为一个弱引用。当ThreadLocal没有强引用时,此key就会变成null被垃圾回收。注意此时value还在,有可能引起内存泄露。只有当调用get或set方法时才能移除。
每个Thread中有这样一个变量
ThreadLocal.ThreadLocalMap threadLocals = null;
当第一次调用set方法时,会将 threadLocals 赋值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
看下createMap方法,会创建ThreadLocalMap,并赋值给线程
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
其中Entry的下标是通过神奇的0x61c88647数,使得均匀分布在2的n次方的数组上。
再来看下ThreadLocal的get方法。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
已当前线程为key取得ThreadLocalMap ,然后在根据Threadlocal实例取得对应的值并返回。
~~~~~~~~~~
ThreadLocal实现时为什么把Map定义在Thread对象里存成Map
而不是定义在ThreadLocal里存成Map
第一种方式在set的时候这么写
Map map = Thread.currentThread().threadLocalMap;
map.put(this,obj);
第二种方式这么写
threadLocalMap.put(Thread.currentThread(),obj);
第二种是多个线程共享一个map,必须处理同步,性能不如第一个高
其他参考
http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/
http://www.cnblogs.com/ilellen/p/4135266.html