这次的博客带来的是关于ThreadLocal<T>的理解
什么是ThreadLocal呢?根据名称来看,ThreadLocal即线程本地的意思。另外它还是一个范型类,这个范型T,就是threadLocal.set(T)的参数,也是threadLocal.get()、threadLocal.initialValue()的返回值。
public class ThreadLocal<T> {
omitted ......
}
那么ThreadLocal又是如何区分不同线程的呢?
在ThreadLocal类内,还有一个静态内部类ThreadLocalMap
// ThreadLocalMap is a customized hash map suitable only for
// maintaining thread local values.
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
omitted ......
}
这个内部类,是一个自定义的hashmap,内部Entry的构造函数需要一个ThreadLocal,以及与这个ThreadLocal关联的对象。
但是我们又会发现,ThreadLocalMap类的实例却没有在ThreadLocal中声明,而是在Thread类中
public class Thread implements Runnable {
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
omitted ......
}
每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,value是真正需要存储的Object。
所以知道了,在ThreadLocal中并没有进行copy操作,不像以前理解的拷贝副本那样,下面举一个例子:
public class ThreadLocalTest {
private static People people = new People();
private static ThreadLocal<People> threadLocal = new ThreadLocal<People>(){
public People initialValue(){
return people;
}
};
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.get().age = 5;
System.out.println("people = " + threadLocal.get() + "age = " + threadLocal.get().age);
}
}).start();
Thread.sleep(10);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("people = " + threadLocal.get() + "age = " + threadLocal.get().age);
}
}).start();
}
}
class People {
public int age;
}
这样一来,在任何一个thread中修改people对象的age,都能够在另外的一个线程中看到
打印结果:
people = thread.People@6f5ab880age = 5
people = thread.People@6f5ab880age = 5
如果将threadLocal中的initialValue()的返回值改为new People,那么才不会相互影响
private static ThreadLocal<People> threadLocal = new ThreadLocal<People>(){
public People initialValue(){
return new People();
}
};
打印结果为:
people = thread.People@44bacfa2age = 5
people = thread.People@44bacfa2age = 0
当然,文章还有很多没有讲,比如如何set,不过不想继续贴源码了,到此为止