车驰夜幕|面试时被问到ThreadLocal别慌,你要的答案都在这里( 三 )


接下来 , 我们再回到ThreadLocal类 , 常用的其实就下面四个方法:get() ,initialValue() , set(T value) 和 remove() , 接下来我们会逐一介绍 。
首先看看get()方法
public T get() {//获取当前线程Thread t = Thread.currentThread();//获取当前线程中的ThreadLocalMap对象ThreadLocalMap map = getMap(t);//如果可以查询到数据if (map != null) {//从ThreadLocalMap中获取entry对象ThreadLocalMap.Entry e = map.getEntry(this);//如果entry存在if (e != null) {@SuppressWarnings("unchecked")//获取entry中的值T result = (T)e.value;//返回获取到的值return result;}}//调用初始化方法return setInitialValue();}其中的getMap方法
ThreadLocalMap getMap(Thread t) {return t.threadLocals;}再简单不过了 , 直接返回的是当前线程的成员变量threadLocals
再看看getEntry方法
private Entry getEntry(ThreadLocal key) {//threadLocalHashCode是key的hash值//key.threadLocalHashCode//获取下标对应的entryEntry e = table[i];//如果entry不为空 , 并且从弱引用中获取到的值(threadLocal) 和 key相同if (e != nullelse//如果没有获取到entry或者e.get()获取不到数据 , 则清理空数据return getEntryAfterMiss(key, i, e);}我之前说过entry是WeakReference的子类 , 那么e.get()方法会调用:
public T get() {return this.referent;}返回的是一个引用 , 这个引用就是构造器传入的threadLocal对象 。
车驰夜幕|面试时被问到ThreadLocal别慌,你要的答案都在这里getEntryAfterMiss里面有说明逻辑呢?
private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {Entry[] tab = table;int len = tab.length;while (e != null) {ThreadLocal k = e.get();if (k == key)return e;if (k == null)expungeStaleEntry(i);elsei = nextIndex(i, len);e = tab[i];}return null;}该方法里面会调用expungeStaleEntry方法 , 后面我们会重点介绍的 。
再看看setInitialValue方法
protected T initialValue() {return null;}private T setInitialValue() {//调用用户自定义的initialValue方法 , 默认值是nullT value = http://kandian.youth.cn/index/initialValue();//获取当前线程Thread t = Thread.currentThread();//获取当前线程中的ThreadLocalMap , 跟之前一样ThreadLocalMap map = getMap(t);//如果ThreadLocalMap不为空 ,if (map != null)//则覆盖key为当前threadLocal的值map.set(this, value);else//否则创建新的ThreadLocalMapcreateMap(t, value);//返回用户自定义的值return value;}当中的initialValue()方法 , 就是我们要介绍的第二个方法
protected T initialValue() {return null;}我们可以看到该方法只有一个空实现 , 等着用户的子类重写之后重新实现 。
接下来重点看看threadLocalMap的set方法
private void set(ThreadLocal key, Object value) {//将table数组赋值给新数组tabEntry[] tab = table;//获取数组长度int len = tab.length;//跟之前一样计算数组中的下表int i = key.threadLocalHashCode//循环变量tab获取entryfor (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {//获取entry中的threadLocal对象ThreadLocal k = e.get();//如果threadLocal对象不为空 , 并且等于keyif (k == key) {//覆盖已有数据e.value = http://kandian.youth.cn/index/value;//返回return;}//如果threadLocal对象为空if (k == null) {//创建一个新的entry赋值给已有keyreplaceStaleEntry(key, value, i);return;}}//如果key不在已有数据中 , 则创建一个新的entrytab[i] = new Entry(key, value);//长度+1int sz = ++size;if (!cleanSomeSlots(i, sz) }