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
欢迎关注我公众号: