本文转载自微信公众号三不猴子《三不猴》。转载本文请联系三部猴公众号。为什么ThreadLocal容易出现内存泄露?什么是线程本地?官方的解释是:该类提供线程局部变量。这些变量与它们的普通对应变量的不同之处在于,每个访问一个变量(通过其get或set方法)的线程都有其自己的、独立初始化的变量副本。我们平时创建的变量可以被任何线程访问和修改,但是用ThreadLocal创建的变量只能被当前线程访问和修改。ThreadLocal原理jdkversion1.8,我们先看看ThreadLocal的源码,先从set方法说起。/***将当前线程的此线程局部变量副本*设置为指定值。大多数子类将不需要*重写此方法,仅依赖于{@link#initialValue}*方法来设置值软线程局部变量。**@paramvalue将值存储在当前线程的*此线程局部副本中。*/publicvalue=Threadt{TcurrentThread();ThreadLocalMapmap=getMap(t);if(map!=null)map.set(this,value);elsecreateMap(t,value);}这个ThreadLocalMap是ThreadLocal的一个内部类,key是当前的Thread对象,value是我们要保存的对象。先获取当前线程对象,然后获取一个map,然后将当前ThreadLocal对象放入map中,如果map为空,则创建一个map。看getMap的逻辑。/***GetthemaassociatedwithaThreadLocal.Overriddenin*InheritableThreadLocal.**@paramtthecurrentthread*@returnthemap*/ThreadLocalMapgetMap(Threadt){return.threadLocals;}getMap是获取Thread成员变量中的一个map。接下来是ThreadLocalMap.set(),看看set的逻辑。/***Setthevalueassociatedwithkey.**@paramkeythethreadlocalobject*@paramvaluethevaluetobeset*/privatevoidset(ThreadLocal>key,Objectvalue){//我们不使用快速路径aswithget()因为它在//leastascommontouseset()来创建新条目as//itisoreplaceexistingones,inwhichcase,afastreft/path。Entry[]tab=table;intlen=tab.length;inti=key.threadLocalHashCode&(len-1);for(Entrye=tab[i];e!=null;e=tab[i=nextIndex(i,len)]){ThreadLocal>k=e.get();if(k==key){e.value=value;return;}if(k==null){replaceStaleEntry(key,value,i);return;}}tab[i]=newEntry(key,value);intsz=++size;if(!cleanSomeSlots(i,sz)&&sz>=threshold)rehash();}这里构造了一个Entry对象,这个Entry就可以了可以看成一行map数据,一个key-valuepair。查看Entry的源代码。staticclassEntryextendsWeakReference
