ThreadLocal大家都知道是线程局部变量。今天stackmanager再介绍一个神器:FastThreadLocal,字面意思:Fast+ThreadLocal,一个快速的ThreadLocal?这到底是什么?一、FastThreadLocal简介FastThreadLocal并不是JDK自带的,而是Netty内置的一个轮子。为什么Netty会重复造轮子?查看其源码中的注释定义:/***Aspecialvariantof{@linkThreadLocal}thatyieldhigheraccessperformancewhenaccessedfroma*{@linkFastThreadLocalThread}。*
*在内部,{@linkFastThreadLocal}使用常量索引数组,而不是使用哈希码和哈希表,*寻找变量。虽然看起来非常微妙,但ityieldss轻微的性能优势超过使用哈希*表,并且在经常访问时很有用。*
*要利用这个线程局部变量,你的线程必须是线程。由于这个原因,由{@linkDefaultThreadFactory}创建的所有线程都是{@linkFastThreadLocalThread}。*
*请注意,fastpathisonlypossibleonthreadsthatextend{@linkFastThreadLocalThread},因为它需要*一个specialfieldtostorethenecessarystate.Anaccessbyanyotherkindofthreadfallsbacktoregular*{@linkThreadLocal}.*
**@param
thetypeofthethread-localvariable*@seeThreadLocal*/publicclassFastThreadLocal{...}FastThreadLocal是一种特殊的ThreadLocal变体,当从thread在类FastThreadLocalThread中访问FastThreadLocalm可以获得更高的访问性能如果你不知道ThreadLocal是什么,可以关注公众号Java技术栈阅读我之前分享的文章。2、FastThreadLocal为什么快?在FastThreadLocal内部,使用索引常量代替HashCode和哈希表。源码如下:getAndIncrement();if(index<0){nextIndex.decrementAndGet();thrownewIllegalStateException("toomanythread-localindexedvariables");}returnindex;}FastThreadLocal内部维护了一个索引常量index,每次创建FastThreadLocal时自动+1,因此确保下标的不可重复性。这样虽然会产生大量的索引,但是避免了在ThreadLocal中计算索引下标位置和处理hash冲突带来的损失。因此,在操作数组时使用固定下标比计算散列下标代价更大。性能优势,尤其是经常使用的时候,会非常显着,用空间换取时间,这就是高性能Netty的巧妙之处。要利用FastThreadLocal带来的性能优势,需要结合使用FastThreadLocalThread线程类或其子类,因为FastThreadLocalThread线程类会存储必要的状态,如果使用非FastThreadLocalThread线程类,会退回到常规的ThreadLocal。Netty提供了实现接口的继承类和线程类:FastThreadLocalRunnableFastThreadLocalThreadNetty还提供了一个DefaultThreadFactory工厂类。DefaultThreadFactory工厂类创建的所有线程都默认为FastThreadLocalThread类型。看一下它的创建过程:先创建FastThreadLocalRunnable,再创建FastThreadLocalThread,小伙伴们干活不累,要一起用才能“快”。三、FastThreadLocal实战要使用FastThreadLocal就需要导入Netty的依赖了:io.nettynetty-all4.1.52.Final写一个测试小示例:importio.netty.util.concurrent.DefaultThreadFactory;importio.netty.util.concurrent.FastThreadLocal;publicclassFastThreadLocalTest{publicstaticfinalintMAX=100000;publicstaticvoidmain(String[]args){newThread(()->threadLocal()).start();newThread(()->fastThreadLocal()).start();}privatestaticvoidfastThreadLocal(){longstart=System.currentTimeMillis();DefaultThreadFactorydefaultThreadFactory=newDefaultThreadFactory(FastThreadLocalTest.class);FastThreadLocal[]fastThreadLocal=newFastThreadLocal[MAX];for(inti=0;i();}Threadthread=defaultThreadFactory.newThread(()->{for(inti=0;i[]threadLocals=newThreadLocal[MAX];for(inti=0;i();}Threadthread=newThread(()->{for(inti=0;i