ThreadLocal和Sychronized都用于解决多线程间的并发访问,但它们实现的本质方法不同:sychronized利用锁使同一个代码块或变量在某时刻只能被一个线程访问,而ThreadLocal则为所有线程都提供一个变量副本,这样在某一时刻不同线程访问到的是本质上不同的变量。
ThreadLocal的底层是一个TMap(ThreadLocalMap),向ThreadLocal中存东西相当于向TMap中存东西.
存东西:(当前线程id,TMap)->得到TMap->TMap(当先线程id,保存的值),从当前线程id获取TMap,得到TMap之后, 往TMap里面存值
ThreadLocalMap tmap=getMap(Thread.currentThread());//(当前线程id,TMap)
tmap.set(this,value);//(当先线程id,保存的值)
取东西:(当前线程id,TMap)->得到TMap->TMap(当先线程id,保存的值),从当前线程id获取TMap,得到TMap之后,从TMap里面取值
ThreadLocalMap tmap=getMap(Thread.currentThread());//(当前线程id,TMap)
ThreadLocalMap.Entry entry=tmap.getEntry(this);//(当先线程id,保存的值)
Object ob=entry.value;//(当先线程id,保存的值)
- 使用场景:数据库连接、session管理、父子线程共享线程变量(我使用过的token)
- 数据库连接
测试:
主线程中定义static型的ThreadLocal,上面代码中每个线程第一次获取connection时,都会往ThreadLocal中存一份自己的connection,往后直接用就可以了
(1)内存泄漏:TMap(当先线程id,保存的值)中的key为ThreadLocal弱引用,在系统GC的时候,若没有强引用去引用这个弱引用,这个弱引用就会被回收掉,则key就会变为null,这样TMap中就会出现key为null的Entry,也就不能访问到key为null的Entry对应的value,此时若线程迟迟不结束(使用static型ThreadLocal时,生命周期不会随线程结束而结束),则key为null的Entry对应的value永远无法访问,造成内存泄漏。
解决方法:在不同线程的TMap中清除key=null的value
(2)脏数据:线程池会复用Thread对象,故而Thread对象中的static静态属性ThreadLocal也会被复用,所以需要显示调用remove()清理掉静态属性ThreadLocal的信息,否则若下一个复用的线程若不调用set()设置该线程初始值,而直接调用get()就会获取到它前一个线程设置的值
标签:TMap,场景,value,ThreadLocal,线程,key,注意事项,id
来源: https://www.cnblogs.com/afei1759/p/14618176.html