ThreadLocal的作用
Java对象是线程间共享的,但有时我们需要一些线程间隔离的对象,该对象只能由同一个线程读写,对其他线程不可见。ThreadLocal正式提供了这样的机制,详细使用方式请参考Java ThreadLocal。
ThreadLocal实现原理
自定义实现
在没有看源码前,如果我自己实现一个ThreadLocal,可能是这样的
public class ThreadLocal<T> {
private Map<Thread, T> values = new WeakHashMap<Thread, T>();
public synchronized void set(T value) {
values.put(Thread.currentThread(), value);
}
public synchronized T get() {
return values.get(Thread.currentThread());
}
}
JDK实现
Java源码中ThreadLocal的核心代码如下:
public class ThreadLocal<T> {
public T get() {
Thread t = Thread.currentThread();
//从当前的Thread对象中取出ThreadLocalMap成员,key是ThreadLocal,value是set的值。
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
//从当前的Thread对象中取出ThreadLocalMap成员,key是ThreadLocal,value是set的值。
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
}
//threadLocals变量存放在Thread对象中
public class Thread{
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
...
}
不同于自定义实现,源码中ThreadLocal.set(T value)的值是由Thread对象来缓存的。那么问题就来了?
1. 为什么ThreadLocal.set(T value)的值由Thread对象来缓存,为什么不像自定义实现那样放在ThreadLocal中?
我理解主要是性能考虑。如果放在ThreadLocal中,由于多线程操作同一个Map对象,将不得不加锁保护。而将value直接放在Thread对象中,不同的线程有各自的Thread对象,因此也就无需加锁。因此将value放在Thread对象中性能会好一些。大家如果有不同的见解,请指教^_^
2. 既然value存放在Thread中,为什么不直接由Thread提供getter/setter接口,而需要额外有一个ThreadLocal类?
我理解此处的value虽然和Thread之间存在映射关系,但是不属于Thread的属性,放在ThreadLocal更多是性能上的考虑,因此由Thread提供getter/setter并不适合。
InheritableThreadLocal原理
InheritableThreadLocal中存放的value是当前线程和当前线程创建出来的子线程可见的。其核心源码如下。
public class Thread {
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
...
Thread parent = currentThread();
...
//将parent的inheritableThreadLocals同步到child
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
//此处create一个新的ThreadLocalMap对象
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
}
由于child.inheritableThreadLocals是新创建的ThreadLocalMap对象,因此在child中再次执行set,不会影响parent。
参考文献
- Java ThreadLocal http://tutorials.jenkov.com/java-concurrency/threadlocal.html