ThreadLocal

ThreadLocal

作用

实现线程范围内的局部变量,即ThreadLocal在一个线程中是共享的,在不同线程之间是隔离的。

原理

  • ThreadLocal存入值时使用当前ThreadLocal实例作为key(并不是以当前线程对象作为key),存入当前线程对象中的 ThreadLocalMap中去。

在这里插入图片描述

ThreadLocalMap属性介绍

  • 和普通 Hashmap类似存储在一个数组(Entry类型的数组)内,但与 hashmap使用的拉链法解决散列冲突不同的是 ThreadLocalMap使用开放地址法
  • 数组 初始容量16,负载因子2/3
  • node节点 的 key封装了弱引用用于回收

ThreadLocalMap中Key(引用、内存泄漏)

key的引用问题(两种泄露)

(当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。)

  • 如果key使用引用

1.业务代码中使用完ThreadLocal ,threadLocal Ref被回收了

​ 2.因为threadLocalMap的Entry强引用了threadLocal,造成threadLocal无法被回收

​ 3.在没有手动删除这个Entry以及CurrentThread依然运行的前提下,Entry就不会被回收(Entry中包括了ThreadLocal实例和value),导致Entry内存泄漏 --------key引起的内存泄漏

  • 如果key使用引用

1.业务代码中使用完ThreadLocal ,threadLocal Ref被回收了
​ 2.由于ThreadLocalMap只持有ThreadLocal的弱引用,没有任何强引用指向threadlocal实例,所以threadlocal就可以顺利被 gc回收,此时Entry中的key=null,但是对应的value的引用是强引用。正常情况下,当线程结束,Value就没有了任何强引用,此时可以正常垃圾回收掉。

​ 3.在没有手动删除这个Entry以及 CurrentThread依然运行的前提下,即线程迟迟不结束,而Value早就不再使 用,由于Entry的强引用,Value不会被垃圾回收掉,导致value内存泄漏 -----------Value引起的内存泄漏

由于ThreadLocalMap的生命周期跟Thread一样长,如果都没有手动删除对应key,都会导致内存泄漏,但是使用弱引用可以多一层保障。

出现内存泄漏的真实原因

1.没有手动删除对应的Entry节点信息

2.ThreadLocal 对象使用完后,对应线程仍然在运行

避免内存泄漏的方式
  1. 使用完ThreadLocal,调用其remove方法删除对应的Entry

(虽然ThreadLocal有expungeStaleEntry()方法清除key为null的元素。但是可以看出循环退出的条件为遇到null的元素,因此null之后的并且key为null的元素无法被清除。并且这种清除方式是不及时的。)

  1. key弱引用
  2. 及时调用set、get方法(ThreadLocal 设计在执行 set、get、remove 等方法时,会扫描 key 为 null 的 Entry,如果发现某个 Entry 的 key 为 null,则代表它所对应的 value 也没有作用了,所以它就会把对应的 value 置为 null,这样,value 对象就可以被正常回收了。)

ThreadLocal与synchronized的区别

1、Synchronized用于线程间的数据共享,而 ThreadLocal则用于线程间的数据隔离。

2、Synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而 ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值