栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ThreadLocal

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ThreadLocal

ThreadLocal

文章目录
  • ThreadLocal
    • 面试题
    • 简介
    • API介绍
      • initialValue()
      • withInitial()
      • set()
      • get()
      • remove()
    • 源理分析
    • 强软弱虚四个引用
    • Key键问什么要用弱引用
    • 清除脏Entry
    • 总结

面试题
  1. ThreadLocal中的ThreadLocalMap的数据结构和关系
  2. ThreadLocal的key是弱引用,这是为什么
  3. ThreadLocal内存泄漏问题
  4. ThreadLocal中最后为什么要加remove方法
简介

ThreadLocal提供线程局部变量,这些变量与正常的变量不一样,每一个线程访问ThreadLocal实例的时候都有自己的,独立初始化的变量副本.ThreadLocal实例通常是类中的私有静态字段.

实现每一个线程都有自己专属的本地变量副本 (自己用自己的变量,不和其他线程共享),避免了线程问题.

API介绍 initialValue()

protect T initialValue() 返回此线程局部变量的当前线程的初始值,通常使用匿名内部类,不推荐使用

为每个线程设置初始值

ThreadLocal saleVolume = new ThreadLocal(){
    @Override
    protected Integer initialValue() {
        return 0;
    }
};
withInitial()

为每个线程设置初始值 推荐使用这种方式对每个线程进行初始化赋值

ThreadLocal saleVolume = ThreadLocal.withInitial(() -> 0);
set()

设置当前线程的变量副本值

get()

获取当前线程的变量副本值

remove()

删除此线程局部变量的当前线程值

注:必须回收自定义的ThreadLocal变量,尤其是在线程池的场景下,线程经常会被复用,如果不清理自定义的ThreadLocal变量,可能会影响后续业务逻辑和造成内存泄漏问题

源理分析

问题解决:Thread ThreadLocal ThreadLocalMap之间的关系

线程类中包含了ThreadLocal ,ThreadLocal 中包含了ThreadLocalMap静态内部类

ThreadLocal是一个泛型类,保证可以接受任何类型的对象,ThreadLocal中维护了一个Map的静态内部类,我们使用set,get方法其实都是这个ThreadLocalMap类中对应的get,set方法

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

最终的变量放在了线程的ThreadLocalMap中,并不是存在ThreadLocal上,ThreadLocal作为key

强软弱虚四个引用

强引用:无论任何情况下,只要强引用关系还存在,垃圾回收器就不会回收该对象,例如Object o = new Object();这种引用关系为强引用

软引用:在将发生内存溢出之前,将会把这些对象列为回收范围,垃圾回收时并且达到内存溢出情况会将这些对象进行回收

弱引用:在将发生垃圾回收时,不管会不会发生内存溢出,都会将此类对象进行垃圾回收

虚引用:表示已经回收的对象,为对象设置虚引用关联的唯一目的就是在这个对象被垃圾收集器时收到一个系统通知

Key键问什么要用弱引用

ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal的外部强引用为null了,此时ThreadLocal的外部强引用一定会被垃圾回收掉

ThreadLocal s = new ThreadLocal<>();
s.set("hello");
s.get();

s.set()方法建立一个entry节点,假设方法执行完,栈帧被销毁,s也就没有了,但是此时ThreadLocalMap中的entry中的key引用还指向这个对象,如果这个key为强引用,就会导致key指向ThreadLocal对象不能被垃圾回收,造成内存泄漏

清除脏Entry

这个key为弱引用就大概率的减少内存泄漏问题,ThreadLocal对象在方法执行完毕后顺利被回收且Entry的key引用指向就为null

当我们往ThreadLocal变量赋值,实际上就是当前的Entry(ThreadLocal为key,value为值)往ThreadLocalMap中存放,Entry中的key是弱引用,当threadLocal外部引用被置为null,当GC的时候,这个ThreadLocal就会被回收,这时key为null,value还存在,就没有办法访问这些key为null的Entry值,如果线程不结束,这时存在很多key为null的entry,value无法回收,造成内存回收(线程复用 线程池)

调用get,set,remove方法时,就会尝试删除key为null的entry,可以是否value对象占用的内存

总结

ThreadLocal通常用static关键字修饰,ThreadLocal能实现线程隔离,不在于它自己本身,而是在于Thread的ThreadLocalMap,所以,ThreadLocal可以只初始化一次,只分配一块存储空间,没必要作为成员变量多次被初始化

  • ThreadLocal并不解决线程间共享数据问题
  • 适用于变量在线程间隔离且在方法间共享的场景
  • 每个线程持有一个只属于自己的专属map并维护了ThreadLocal对象与具体实例的映射
  • ThreadLocalMap的Entry对ThreadLocal是弱引用,避免了ThreadLocal对象无法回收的问题
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/992752.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号