ThreadLocal的理解

ThreadLocal的作用

存在问题:可用于解决线程安全问题。

解决方案:每个线程保存一份自己的对象,ThreadLocal这个作用就是让线程自己独立保存一份自己的变量副本。每个线程都独立使用自己的变量副本,这样就不会影响其他的线程。

也就是说每个线程都会复制一份对象到自己的线程里面去,线程之间是隔离的,所以不会出现线程之间使用同一份资源而造成问题。

ThreadLocal是为多线程环境下变量安全提供的一种解决思路,ThreadLocal是为每个线程建立一份自己的单独的变量副本。

每个线程都可以独立地去改变自己的变量副本,从而不会影响其他的线程。ThreadLocal内部有个非常重要的内部类——ThreadLocalMap,该类是实现线程隔离的关键

ThreadLocalMap

内部类似于map,但不是map,它是由键值对key、value组成的一个Entry数组,key是ThreadLocal本身的一个弱引用value就是对应的线程变量副本

ThreadLocal本身是不存储值的,他只是提供一个能查到这个值的key

ThreadLocal包含在这个Thread中,而不是Thread包含在ThreadLocal中。

ThreadLocal的理解_第1张图片
这个类图左边是Thread,他有内部属性threadLocals,这个属性其实就是指向这个ThreadLocal,右边这部分他是一个ThreadLocal,ThreadLocal里面,他又包含这个内部类,内部就是由这个Entry数组组成。每个Entry由key、value组成的。

  1. key就是ThreadLocal这个弱引用。
  2. value就是存进来的这个变量副本。
    ThreadLocal的理解_第2张图片
    ThreadLocalMap是由一个Entry数组组成,然后每一个Entry里面是由这个key、value组成的。它的key是ThreadLocal的这个引用,value是实际存储的值。

堆和栈之间的关系图

左边是一个栈,里面放了一个ThreadLocal的引用和一个当前线程的引用。
ThreadLocal的理解_第3张图片
当前线程是一个ThreadLocalMap,ThreadLocalMap里面分为key和value,key和value组成一个entry。他的value是一个50M的值,key是由threadlocal去引用的(一个弱引用的关系)。

每一个Thread线程内部都有一个ThreadLocalMap,这个map里面,key是ThreadLocal这个引用,他的value就是你要操作的这个变量值。Thread内部的ThreadLocalMap是由这个ThreadLocal去维护的。由这个ThreadLocal负责向这个map里面去设置值,添加值,删除值等等操作。

ThreadLocal中的方法

get()方法

用来获取ThreadLocal在当前线程中保存的变量副本。

  1. 获取当前线程,去获取到这个ThreadLocalMap
  2. 通过这个线程里面的threadLocals去拿到这个ThreadLocalMap,然后拿到的map不为空,那么就把这个值拿出来返回。如果没有取到这个值,就初始化这个值。

set()方法

用来设置当前线程中变量的副本。把当前线程中的ThreadLocalMap拿出来,如果这个map值不为空,那么就把这个map的值更新一下,如果为空,则创建这个map。

remove()方法

用来移除当前线程中变量的副本。

initialValue()方法

一个protected方法,一般是用来在使用时进行重写的。

数据结构

数组+开放地址法

内存泄露问题

ThreadLocal的理解_第4张图片
Entry继承这个弱引用的时候,只是对key做了弱引用,对value还是强引用。弱引用能帮助程序更好地去进行垃圾回收。

如果一个ThreadLocal没有外部强引用来引用它,那么下一次系统GC的时候,这个ThreadLocal弱引用肯定是会被回收的。这样一来,这个ThreadLocalMap就出现了key为null的Entry,也就没有办法通过这个key找到value,然后这个value又是强引用的,如果线程一直存在的话,他就会一直存在这个value,就会造成内存泄露的问题,一直不会被GC掉,被垃圾回收掉。

get方法,set方法还有remove方法会对这个key为null的Entry进行清除。

如何避免内存泄露

使用完ThreadLocal后就手动地调用remove方法即可。

参考资料:【真实工作场景】中怎么用ThreadLocal

你可能感兴趣的:(Java,jvm,java,开发语言)