当前位置: 首页 > 后端技术 > Java

详细解释什么是ThreadLocal

时间:2023-04-01 21:24:03 Java

ThreadLocal。ThreadLocal类提供线程局部变量的实现。与所有线程都可以访问的全局变量不同,ThreadLocal中的变量是线程私有的,只能被当前线程访问。ThreadLocal可以做什么:为每个线程生成一个唯一的标识符;第一次调用ThreadId.get()时会分配线程ID。第一次调用get方法时,会触发initialValue生成初始值。导入java.util.concurrent.atomic.AtomicInteger;公共类ThreadId{privatestaticfinalAtomicIntegernextId=newAtomicInteger(0);//生成每个线程的IDprivatestaticfinalThreadLocalthreadId=newThreadLocal(){@OverrideprotectedIntegerinitialValue(){returnnextId.getAndIncrement();}};//返回线程的唯一标识;publicstaticintget(){返回threadId.get();}}以上案例可以推导出其他适用的场景,比如logintoken信息的传递等。ThreadLocal是如何实现线程局部变量的呢?看到这里,你肯定也看到了,但是你心里还是有疑惑。ThreadLocal为什么可以实现线程局部变量?数据是如何存储的?那么,上图首先说明了它的存储结构和局部变量的实现原理,然后通过关键方法的源码分析来支持和印证我们的说法。从图中我们可以看出,每个线程都持有一个ThreadLocalMap对象。ThreadLocalMap内部有一个数组,数组对象为Entry。Entry的key就是ThreadLocal对象,value就是我们设置的具体值。通过为每个线程持有一个单独的ThreadLocalMap对象,并在这个对象中设置相应的值,实现了线程私有的局部变量的设置和获取。下面我们通过源码看看如何设置、获取、删除局部变量。set(Tvalue)publicvoidset(Tvalue){//获取当前线程Threadt=Thread.currentThread();//获取当前线程的ThreadLocalMap对象ThreadLocalMapmap=getMap(t);if(map!=null)map.set(this,value);否则createMap(t,value);}ThreadLocalMapgetMap(Threadt){返回t.threadLocals;}voidcreateMap(Threadt,TfirstValue){t.threadLocals=newThreadLocalMap(this,firstValue);}set方法通过获取当前线程的ThreadLocalMap对象,以ThreadLocal为key来设置value为value。ThreadLocalMap可以简单理解为一个map。由于不是本文的重点,有兴趣的朋友可以参考源码了解ThreadlocalMap的详细内容。get()publicTget(){线程t=Thread.currentThread();ThreadLocalMapmap=getMap(t);//获取ThreadLocalMap对象后取值if(map!=null){ThreadLocalMap.Entrye=map.getEntry(这个);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);返回值;}//默认初始值生成为null,可以重写该方法设置初始值,如上例。protectedTinitialValue(){返回空值;}get方法是获取当前线程的ThreadLocalMap对象,然后去对应的值。如果获取到的ThreadLocalMap值为null,则将initialValue()返回的值设置为ThreadLocalMap并返回。remove()publicvoidremove(){ThreadLocalMapm=getMap(Thread.currentThread());如果(m!=null)m.remove(this);}获取当前线程的ThreadLocalMap值,并删除对应的值。使用ThreadLocal避免读取脏数据。现在代码中常用线程池。线程池中的线程是可重用的。假设该值是使用ThreadLocal设置的。如果不执行remove操作,下次换线程。再次取值,get方法取值是上次设置的值。处理方法:使用后进行移除操作。避免内存泄漏使用线程池后,由于线程一直存在,相应的值无法被垃圾回收,容易出现内存泄漏。处理方法:使用后进行移除操作。