ThreadLocal介绍:
ThreadLocal是Thread的一个局部变量,主要用于一个线程在业务流程相对复杂的情况下,进行数据的存储和使用,比如:用户的登录信息,锁的信息等。
ThreadLocal使用:
在定义ThreadLocal时要将其设置为静态变量(原因后面解释)
static ThreadLocal<String> lockThreadLocal = new ThreadLocal<>();
复制代码
使用时利用set和get进行设置、获取值
⚠️注意:ThreadLocal存储的对象不需要使用线程安全类型,因为ThreadLocal本身是线程安全的
ThreadLocal原理:
每个Thread中都有一个ThreadLocal.ThreadLocalMap对象。在ThreadLocalMap中,也是初始化一个大小16的Entry数组,Entry对象用来保存每一个key-value键值对,key为弱引用指向的ThreadLocal对象,value为ThreadLocal set的值。
如下图:
由于ThreadLocalMap的key是WeakReference指向的,如果没有外部强引用指向,在下一次发生gc的时候就会被回收,当ThreadLocal在进行set或get操作时会清理key为null的entry,这样虽然可以一定程度上防止内存泄漏,但是如果在ThreadLocal后没有进行get和set操作,entry中的value就不会回收,而在tomcat容器中,使用的是线程池,当前线程使用完后不会进行回收,进入线程池等待下次调用,这样就会导致内存泄漏,所以在使用完后要进行remove操作。关于ThreadLocal对象是否设置为static的利弊:
static:
优点 减少了ThreadLocal对象的创建,并且降低了因重复创建ThreadLocal导致的数据错乱
缺点 ThreadLocal.ThreadLocalMap的弱引用无法生效,如果ThreadLocal忘记remove,则会造成key一直存在,value无法回收(虽然ThreadLocal被gc变成null,也不能确保一定不会发生内存泄漏)
非static:
优点 由于ThreadLocal.ThreadLocalMap的key是弱引用,在线程执行完后,会断开ThreadLocal的链路,这样ThreadLocal不可达就会被gc
缺点 对象多,而且因为ThreadLocal多容易造成取数错误,因为ThreadLocal是key(容易导致bug)
结论:建议ThreadLocal设置为static对象,在使用完后进行remove操作,既避免了内存泄漏也避免了由于key使用不当导致的bug。