ThreadLocal的弱引用

我是研究僧i 提交于 2020-02-05 04:51:58

ThreadLocal中,获取到线程私有对象是通过线程持有的一个threadLocalMap,然后传入ThreadLocal当做key获取到对象的,这时候就有个问题,如果你在使用完ThreadLocal之后,将其置为null,这时候这个对象并不能被回收,因为他还有 ThreadLocalMap->entry->key的引用,直到该线程被销毁,但是这个线程很可能会被放到线程池中不会被销毁,这就产生了内存泄露,jdk是通过弱引用来解决的这个问题的,entry中对key的引用是弱引用,当你取消了ThreadLocal的强引用之后,他就只剩下一个弱引用了,所以也会被回收。

看代码 threadLocal是一个强引用,引用了堆中ThreadLocal对象A,然后调用set方法时,在当前线程的threadLocalMap中也引用了对象A,即entry中的key,如果entry中的key不设为弱引用的话,就会存在上面说的对象A内存泄露的问题。

ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
threadLocal.set(1);
threadLocal.get();
threadLocal = null;



作者:吕清海
链接:https://www.zhihu.com/question/37401125/answer/337717256
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

ThreadLocal在解决完Entry中的key内存泄露问题后,还有一个内存泄露问题,就是Entry中的value

因为只有key是弱引用,当上面threadLocal强引用变空时,entry.key也会被回收,这个时候还剩下Entry和Entry中的value。

因为entry是跟threadLocalMap绑定在一起的,threadLocalMap又是跟Thread绑定在一起的。所以只要线程没销毁的话,这个entry就不会被销毁,这样就内存泄露了。

ThreadLocal提供了这个问题的解决方案。

每次操作set、get、remove操作时,ThreadLocal都会将key为null的Entry删除,从而避免内存泄漏。

那么问题又来了,如果一个线程运行周期较长,而且将一个大对象放入LocalThreadMap后便不再调用set、get、remove方法,此时该仍然可能会导致内存泄漏。

这个问题确实存在,没办法通过ThreadLocal解决,而是需要程序员在完成ThreadLocal的使用后要养成手动调用remove的习惯,从而避免内存泄漏。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!