8、ThreadLocal入门介绍

2020-06-07  本文已影响0人  火山_6c7b

1. threadlocal

1.1 解释

ThreadLocal是线程变量,即ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

1.2 作用

1.3 结构

ThreadLocal结构:


ThreadLocal结构.jpeg

说明:每个thread持有一个ThreadLocalMap,里面存储了线程中定义的一系列ThreadLocal,需要取某个threadlocal值时,首先根据currentThread取到threadlocalmap,然后以该threadlocal为key拿到threadlocal的值。

1.4 内存泄漏

ThreadLocal本身并不真正存储线程的变量值,它只是一个工具,用来维护Thread内部的Map,帮助存和取。注意ThreadLocal结构图的虚线,它代表一个弱引用类型,而弱引用的生命周期只能存活到下次GC前。

ThreadLocal在ThreadLocalMap中是以一个弱引用身份被Entry中的Key引用的,因此如果ThreadLocal没有外部强引用来引用它,那么ThreadLocal会在下次JVM垃圾收集时被回收。这个时候就会出现Entry中Key已经被回收,出现一个null Key的情况,外部读取ThreadLocalMap中的元素是无法通过null Key来找到Value的。因此如果当前线程的生命周期很长,一直存在,那么其内部的ThreadLocalMap对象也一直生存下来,这些null key就存在一条强引用链的关系一直存在:Thread --> ThreadLocalMap-->Entry-->Value,这条强引用链会导致Entry不会回收,Value也不会回收,但Entry中的Key却已经被回收的情况,造成内存泄漏。

但是JVM做了一些措施来保证ThreadLocal尽量不会内存泄漏:在ThreadLocal的get()、set()、remove()方法调用的时候会清除掉线程ThreadLocalMap中所有Entry中Key为null的Value,并将整个Entry设置为null,利于下次内存回收。
但这样也并不能保证ThreadLocal不会发生内存泄漏,例如:

1.5 根源及解决

下面我们分两种情况讨论:

比较两种情况,我们可以发现:由于ThreadLocalMap的生命周期跟Thread一样长,如果都没有手动删除对应key,都会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key的value就会导致内存泄漏,而不是因为弱引用。

解决:最简单最有效的解决办法即是显式调用remove(ThreadLocal<?> key).

上一篇 下一篇

猜你喜欢

热点阅读