ThreadLocal原理及内存泄漏原因

        在了解ThradLocal原理前,是有必要需要了解一下java的引用类型的,因为Threadlocal的底层使用了弱引用,可以顺便把这方面的知识过一下,再加上面试的时候,这个也是比较常问的        

1.java引用类型:

        引用类型分别有强,软,弱,虚类型

2.分别说一下这些引用类型的特点

         强引用:在java里面直接new出来的对象属于一个强引用,如果一个对象具有强引用,JVM就不会去进行回收它,当内存空间不够的时候就会报OOM错误

        

        软引用:如果一个对象只具备软引用,那么当内存空间不够的时候,JVM就会把这个对象进行回收(Soft Reference
       

        弱引用:如果一个对象只具备了弱引用,那么被jvm的gc线程检测到了,这个对象就会被回收(Weak Reference)
        

        虚引用:是直接管理本地内存的

3.ThradLocaL

        ThreadLocL是线程的一个局部变量,这种变量可以在多线程的情况下,让数据与当前线程进行绑定,这个数据其他线程是不能进行读取跟修改的,从而确保了线程的安全。

4.set方法的底层原理

             在ThreadLocL调用set方法的时候,set方法底层是先获取到当前线程,然后再通过getmap方法,来获取当前线程的ThreadLocLs变量,然后再把ThradLocL作为key,set方法传进参数作为value,通过ThreadLocLs的set方法保存起来,在保存的时候,key会以弱引用的形式保存起来,value是以强引用的形式进行保存

        所以当Threadlocl调用set方法来保存值的时候,并不是保存的在Threadlocl里面,而是保存在了当前线程的ThreadLocLs变量中(这个变量的类型是ThreadLocalMap),而这个变量是一个map结构,里面的key保存了调用set方法的ThreadLocL引用,value是需要保存的值

5.get方法的底层原理

        ThreadLocL调用get方法,首先会获取当前线程,然后再通过getmap方法,来获取当前线程的ThreadLocLs变量,通过变量的getEntry方法,参数是ThreadLocL,就可以来获取到所保存的数据

6.为什么key要设置为弱引用,强引用不行吗?

       用强引用的话有可能会造成内存泄露,当线程不再需要使用某个Threadlocl的时候,如果key是强引用类型,那么jvm并不能对它进行回收,如果线程一直启动,那么时间长了,有可能会报错oom错误,而弱应用类型不会,只要jvm执行一次gc操作,那么就会进行回收

7.为什么value要设置为强引用,弱引用不行吗?

        如果value是弱引用,只要jvm执行一次gc操作,那么这个value就被回收掉了,取值的时候会返回null,所以只能是强引用

8.内存泄露

        第一种情况:如果key被jvm的gc回收掉了,那么value值就无法被访问,如果线程一直在运行,那么就会有可能造成oom错误,虽然调ThreadLocLMap的set,get方法的时候会把key为null的Entry对象删除掉,但如果这个线程很久都没有进行这两个方法的调用,那也是无法进行回收,所以我们在使用完成之后要手动remove来保证代码的安全性
 

        第二种情况:如果使用了线程池进行线程复用,线程使用完成之后,如果不进行remove操作的话,那么线程的ThreadloclMap保存的值会越来越多,还可能出现value的值被覆盖的情况,所以也需要手动remove操作来保证代码的安全性

9.ThreadLocalMap.Entry中的key为什么不会被错误清理?

         一个对象在只有弱引用指向它时,一旦jvm执行gc操作,那它就会被回收,但是ThreadLocal对象除了在Entry中有弱引用指向,在业务代码中还有强引用指向,所以不会被错误清理

10.ThreadLocal在业务场景中的使用

        全局存储用户信息

 

猜你喜欢

转载自blog.csdn.net/qq_26112725/article/details/129782931