ThreadLocal的实例代表了一个线程局部的变量,每条线程都只能看到自己的值,并不会意识到其它的线程中也存在该变量。
在ThreadLocal类中定义了一个ThreadLocalMap,每一个Thread都有一个ThreadLocalMap,ThreadLocalMap内部有一个Entry数组,key是ThreadLocal,value就是我们定义的变量副本。
例如我们知道SimpleDateFormat是线程不安全的,多线程使用可以使用ThreadLocal
//声明 ThreadLocal<SimpleDateFormat> dateFormatter = new ThreadLocal<SimpleDateFormat>(); //调用 dateFormatter.get().format(result);
1、获取当前线程t;
2、返回当前线程t的成员变量ThreadLocalMap(以下简写map);
3、map不为null,则获取以当前线程为key的ThreadLocalMap的Entry(以下简写e),如果e不为null,则直接返回该Entry的value;
4、如果map为null或者e为null,返回setInitialValue()的值。setInitialValue()调用重写的initialValue()返回新值(如果没有重写initialValue将返回默认值null),并将新值存入当前线程的ThreadLocalMap(如果当前线程没有ThreadLocalMap,会先创建一个)
具体看到源码就知道:
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();
}
在get函数中,首先获取到当前的线程t,再根据t获取ThreadLocalMap。下面试getMap()函数:
ThreadLocalMap getMap(Thread t)
{
return t.threadLocals;
}
如果没有找到对应的map,就会调用setInitialValue创建map
private T setInitialValue()
{
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
可以看到,每个线程都会有对应的 ThreadLocalMap,key为当前的ThreadLocal示例,value为需要设置的值
HashMap使用 链地址法 来解决Hash冲突,而ThreadLocalMap使用 开放地址法 来解决Hash冲突。
public void set(T value)
{
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
set函数同样是先获取ThreadLocalMap类型的变量map。如果不存在就会创建map
void createMap(Thread t, T firstValue)
{
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap定义
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;
}
}
...
}
ref.
https://www.cnblogs.com/xujian2014/p/5777849.html
https://blog.csdn.net/u010887744/article/details/54730556
欢迎关注我公众号: