ThreadLocal我们都很熟悉,它的作用就像它的名字一样——用来存储“线程局部”变量。我们通过一个小例子来感受一下:privatestaticfinalThreadLocalthreadLocal=newThreadLocal<>();publicstaticvoidmain(String[]args)throwsThrowable{ThreadthreadOne=newThread(()->{threadLocal.set("ThreadOne:"+Thread.currentThread().getName());log.info("Thread一个局部变量值:{}",threadLocal.get());threadLocal.remove();log.info("线程一移除后的局部变量值:{}",threadLocal.get());});ThreadthreadTwo=newThread(()->{threadLocal.set("ThreadTwo:"+Thread.currentThread().getName());log.info("线程二的局部变量值为:{}",threadLocal。得到());});threadOne.start();threadTwo.start();}运行结果:threadOne局部变量的值为:ThreadOne:Thread-0。线程一被移除后,局部变量的值为:null。线程隔离呢?让我们看一下源代码,看看它是如何工作的:publicvoidset(Tvalue){Threadt=Thread.currentThread();ThreadLocalMapmap=getMap(t);如果(地图!=null)地图。设置(这个,值);电子lsecreateMap(t,value);}set()方法逻辑如下:获取当前线程根据当前线程获取一个ThreadLocalMap对象。如果地图不为空,则保存它。如果地图为空,则创建地图。getMap()和createMap()方法都是Whatdidyoudo?我们点进去看看:ThreadLocalMapgetMap(Threadt){returnt.threadLocals;}voidcreateMap(Threadt,TfirstValue){t.threadLocals=newThreadLocalMap(this,firstValue);}进入两个方法后,我们发现那不管执行到哪个分支,这个值最终都保存在当前线程的threadLocals属性中。查看Thread类的源码,会发现类中定义了一个threadLocals属性,其初始值为null,其类型为ThreadLocal.ThreadLocalMap。publicclassThreadimplementsRunnable{//...ThreadLocal.ThreadLocalMapthreadLocals=null;//...}此时,我们发现ThreadLocal将我们要传递的对象放到了当前线程的threadLocals属性中。也就是说,每个线程在用ThreadLocal保存一个对象的时候,实际上是把这个对象放到了当前线程实例对象的threadLocals属性中。这样一来,线程自然就相互独立了。再看看get()方法:publicTget(){Threadt=Thread.currentThread();ThreadLocalMapmap=getMap(t);if(map!=null){ThreadLocalMap.Entrye=map.getEntry(this);if(e!=null){@SuppressWarnings("unchecked")T结果=(T)e.value;返回结果;}}returnsetInitialValue();}privateTsetInitialValue(){Tvalue=initialValue();线程t=Thread.currentThread();ThreadLocalMapmap=getMap(t);if(map!=null)map.set(this,value);否则createMap(t,value);returnvalue;}ThreadLocal的get()方法其实和set()方法的逻辑很相似。首先,它取自当前线程的threadLocals属性。如果该属性为空,则对其进行初始化。当线程结束时,调用当前线程实例的exit()方法,将threadLocals设置为null,以便垃圾收集器回收。//THread类中的方法privatevoidexit(){//...threadLocals=null;//...}最后还有一点需要特别注意:使用ThreadLocal后记得手动调用remove()方法,否则可能会产生脏数据甚至内存泄漏。为什么?上面不是说threadLocals会在线程结束时置为null吗?是的,当线程结束时,它确实会进行清理。但是,如果线程永远不会结束怎么办?如果线程将被重用怎么办?例如,使用线程池。因此,在使用ThreadLocal时必须手动remove()。