介绍JDK中的ThreadLocal可以通过get方法获取当前线程绑定的值。而这些值存储在ThreadLocal.ThreadLocalMap中。ThreadLocalMap中的底层数据存储在一个Entry数组中。那么ThreadLocalMap获取数据的速度是多少呢?速度上有优化空间吗?让我们来看看。从ThreadLocalMap中获取数据ThreadLocalMap是一个Map,其底层数据存储是一个Entry类型的数组:privateEntry[]table;让我们回顾一下ThreadLocal是如何获取数据的:privateEntrygetEntry(ThreadLocal>key){inti=key.threadLocalHashCode&(table.length-1);条目e=表[i];if(e!=null&&e.get()==key)返回e;否则返回getEntryAfterMiss(key,i,e);}首先根据ThreadLocal对象中的threadLocalHashCode和表的长度进行取模运算,得到待获取的Entry在表中的位置,然后判断该位置的Entry的key是否与要获取的ThreadLocal对象。如果一致,说明ThreadLocal绑定的对象已经拿到了,直接返回即可。如果没有,您需要重新搜索。再看一下查找逻辑:privateEntrygetEntryAfterMiss(ThreadLocal>key,inti,Entrye){Entry[]tab=table;intlen=tab.length;while(e!=null){ThreadLocal>k=e.get();if(k==key)返回e;如果(k==null)expungeStaleEntry(i);否则i=nextIndex(i,len);e=tab[i];无效的;}getEntryAfterMiss的逻辑是先判断Entry中的对象是否为要获取的对象,如果是则直接返回。如果Entry中的对象为空,则触发清除过期Entry的方法。否则计算下一个要判断的地址,重新判断,直到最终找到要查找的对象。可以看出,如果第一次没有找到要查找的对象,后面可能会遍历多次,导致执行效率较低。那么有什么办法可以提高这个搜索的速度呢?答案是肯定的。之前我们提到过FastThreadLocal,Netty中的本地对象池技术,netty专门为它创建了一个类叫Recycler。虽然Recycler中也使用了ThreadLocal,但是Recycler使用的threadLocal并不是JDK自带的ThreadLocal,而是FastThreadLocal。与之关联的ThreadLocalMap称为InternalThreadLocalMap,与之关联的Thread称为FastThreadLocalThread。netty中的类和JDK中的类的对应关系如下:netty中的对象JDK对象不管快不快,既然是Thread,自然是继承了JDK的Thread:publicclassFastThreadLocalThreadextendsThread和Thread一样,FastThreadLocalThread也有一个ThreadLocalMap叫做InternalThreadLocalMap,这是FastThreadLocalThread的私有属性:privateInternalThreadLocalMapthreadLocalMap;InternalThreadLocalMap还有一个ThreadLocal对象叫slowThreadLocalMap,当fastThreadLocalMap没有生效时使用。接下来,让我们看看为什么这个ThreadLocalMap很快:publicstaticInternalThreadLocalMapget(){Threadthread=Thread.currentThread();if(threadinstanceofFastThreadLocalThread){returnfastGet((FastThreadLocalThread)线程);}else{返回slowGet();从get方法可以看出,如果当前线程是FastThreadLocalThread,则调用fastGet方法,否则调用slowGet方法。slowGet方法是使用传统的ThreadLocal获取:privatestaticInternalThreadLocalMapslowGet(){InternalThreadLocalMapret=slowThreadLocalMap.get();if(ret==null){ret=newInternalThreadLocalMap();slowThreadLocalMap.set(ret);返回ret;我们关注fastGet方法:privatestaticInternalThreadLocalMapfastGet(FastThreadLocalThreadthread){if(threadLocalMap==null){thread.setThreadLocalMap(threadLocalMap=newInternalThreadLocalMap());}返回threadLocalMap;}这里就出现了fast的效果,fastGet直接返回了线程中的InternalThreadLocalMap对象,没有经过任何查找过程。看看FastThreadLocal是如何使用get方法获取具体值的:publicfinalVget(){InternalThreadLocalMapthreadLocalMap=InternalThreadLocalMap.get();对象v=threadLocalMap.indexedVariable(index);if(v!=InternalThreadLocalMap.UNSET){return(V)v;}返回初始化(threadLocalMap);可以看到FastThreadLocal中的get首先调用InternalThreadLocalMap的get方法,直接返回FastThreadLocalThread中的InternalThreadLocalMap对象,速度非常快。然后直接使用FastThreadLocal中的index获取threadLocalMap中存储数据的数组中的元素:publicObjectindexedVariable(intindex){Object[]lookup=indexedVariables;返回索引
