美文网首页
ThreadLocal学习

ThreadLocal学习

作者: 夏天嘚花花 | 来源:发表于2019-11-18 17:54 被阅读0次

ThreadLocal是什么

ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景

ThreadLoacl数据结构

image.png

通过上图可以看出

  • 每一个线程都维护这一个ThreadLocalMap的数组,这个就是实现线程之间互不影响的原因,因为每个线程自己维护了一个Entry。
  • ThreadLocal只是用来管理每个线程中Entry的一个工具,因为真正的ThreadLocalMap是定义在每一个线程中,可以通过ThreadLocal的get,set方法明白这一切
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
##通过Thread.currentThread获取到当前线程
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
}
#设置时候,ThreadLocalMap的key值就是threadLocal,所以后面可以通过ThreadLocal获取到这个entry的value值
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
 }

  • 为啥是一个Entry数组?因为可能你定义了多个ThreadLocal变量,每个ThreadLocal指向一个Entry,这样不同的ThreadLocal可以操作不同的数据
public class ThreadLocalTest {
    static ThreadLocal LOCAL = new ThreadLocal();
    static ThreadLocal LOCAL2 = new ThreadLocal();
}
  • ThreadLocalMap如何解决Hash冲突?ThreadLocalMap是定义再ThreadLocal类中的一个数据结构,他采用的是线性探测的方式而非像HashMap采用链表的模式。所谓线性探测,就是根据初始key的hashcode值确定元素在table数组中的位置,如果发现这个位置上已经有其他key值的元素被占用,则利用固定的算法寻找一定步长的下个位置,依次判断,直至找到能够存放的位置。基于这特点,建议最好Entry[]的数量不要太多,所以这里引出的良好建议是:每个线程只存一个变量,这样的话所有的线程存放到map中的Key都是相同的ThreadLocal,如果一个线程要保存多个变量,就需要创建多个ThreadLocal,多个ThreadLocal放入Map中时会极大的增加Hash冲突的可能
  • 从结构图可以看出,用ThreadLocal时候set进去的对象必须是每个线程单独new出来的,例如先new了一个对象X,然后后面多线程里面set(X),这样其实每一个线程中Entry的Value指向的是同一个对象X,这样会有问题

ThreadLocal内存泄露

image.png

为什么会内存泄漏?

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却已经被回收的情况,造成内存泄漏
从上可以看出导致内存泄露的几个原因:

  • 使用static的ThreadLocal,延长了ThreadLocal的生命周期,可能导致的内存泄漏
  • 分配使用了ThreadLocal又不再调用get()、set()、remove()方法,那么就会导致内存泄漏
  • 由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key的value就会导致内存泄漏,而不是因为弱引用

解决方法

每次使用完ThreadLocal,都调用它的remove()方法,清除数据。如果一个线程执行时间过长,代码上可以将threadlocal用完后马上remove掉,防止后面代码执行过程导致value值一直得不到释放

参考

https://www.jianshu.com/p/98b68c97df9b

相关文章

  • 吾日三省吾身——ThreadLocal深入剖析

    一、学习目标 1、ThreadLocal能解决什么问题? 2、ThreadLocal相比synchronized、...

  • ThreadLocal 深度解析【转】

    以下内容转载自:ThreadLocal 深度解析最近想学习ThreadLocal原理方面知识,通过多篇博客对比学习...

  • ThreadLocal源码解析

    ThreadLocal源码阅读记录,如有不妥,欢迎指出,共同学习,谢谢! 一、简单使用 ThreadLocal可以...

  • ThreadLocal学习

    描述 ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储。ThreadLocal为变量在...

  • ThreadLocal学习

    ThreadLocal是什么和有什么用 ThreadLocal这个类提供线程本地的变量。这些变量与一般正常的变量不...

  • ThreadLocal学习

    简述 实现变量的共享可以使用public static变量的形式,所有的线程都会共享这一变量,如果想要实现每一个线...

  • ThreadLocal学习

    最近在接入易盾的时候,验证码等数据是通过过滤器获取,存储在ThreadLocal中,之后进行处理。ThreadLo...

  • ThreadLocal学习

    Thread 类中存在变量 : ``` ThreadLocal.ThreadLocalMapthreadLocal...

  • ThreadLocal学习

    ThreadLocal是什么 ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的...

  • ThreadLocal学习

    java中涉及到多线程共享数据的时候都必须要考虑线程安全的问题,今天来学习java中非常重要的辅助类——Threa...

网友评论

      本文标题:ThreadLocal学习

      本文链接:https://www.haomeiwen.com/subject/bnubictx.html