您的位置:首页 > 其它

ThreadLocal源码分析

2016-03-29 21:20 447 查看

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() {
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: