ThreadLocal相关使用,神器

130 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云星级博主

📌 擅长领域:全栈工程师、爬虫、ACM算法

💒 公众号:知识浅谈

🔥 联系方式vx:zsqtcc

ThreadLocal相关使用

简介&小结

**ThreadLocal类用来提供线程内部的局部变量,这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。**ThreadLoca实例通常来说都是private static类型的,用于关联线程和线程上下文。

三个方面讨论ThreadLocal:

  1. 线程并发:如果是单线程,也就i用不到ThreadLocal来存储独立于其他线程的变量了,只有在多线程并发情况下,ThreadLocal用处得以体现。
  2. 传递数据:我们可以通过ThreadLocal中存储变量在线程中的不同组件之间传递数据。
  3. 线程隔离:指的是不同线程的ThreadLocal是相互隔离,相互不影响的。

ThreadLocal常用方法

  1. ThreadLocal()方法:创建ThreadLocal对象。
  2. set() 设置当前线程绑定的局部变量
  3. get() 获取当前线程绑定的局部变量
  4. remove() 移除当前线程绑定的局部变量

ThreadLocal和synchronized区别

ThreadLocal

ThreadLocal采用的是空间换时间的方式,在每个线程中可以保存一个变量的副本,保证多线程之间不会相互影响,

**侧重:**多个线程并发执行时数据相互隔离。

synchronized

synchronized采用的是时间换空间的方式,只提供一分变量,但是让多个线程顺序执行,从而达到的互不影响。

**侧重:**多个线程之间资源同步。

ThreadLocal的内部设计

JDK1.8以前的设计

ThreadLocal的底层是使用map进行实现的,map的key是当前线程,value就是当前线程中要存储的变量,每个线程其内部ThreadLocalMap用于存储对应的键值对。

JDK1.8及以后的设计

ThreadLocal的底层是使用map进行实现的,和之前的区别就是map的key使用ThreadLocal存储的。而不再是当前线程Thread,且一个线程中可以有多个 ThreadLocal,存储在 ThreadLocalMap中,同样的 ThreadLocalMap也有初始大小和阈值,初始大小为16,阈值为当前大小的三分之二。 (1)每个Threads线程内部都有一个Map(ThreadLocalMap)

(2)Map里面存储ThreadLocal对象(key)和线程的变量副本(value)

(3)Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。

(4)对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了副本的隔离互不干扰。

内存泄漏及解决方法

弱引用相关问题

ThreadLocalMap结构

ThreadLocalMap中的节点继承的是软引用,ThreadLocalMap没有继承Map接口,采用独立的方式实现map的功能。

弱引用会造成内存泄漏吗?

答案:会就算是弱引用,在垃圾回收的时候ThreadLocal被回收,但是Entry中的还有对应的value,同样还是会照成泄露,只能通过remove把value移除或者线程执行借宿移除。

image-20220526231200687

最终解决方案

避免内存泄露的两种方式:

  1. 使用完ThreadLocal,调用remove方法删除对应的entry
  2. 使用完ThreadLocal ,当前线程也随即结束。

ThreadLocalMap存储的时候Map冲突

底层采用的解决方法:线性探测法,当从图的时候查看下一个位置是否满足要求,超过map的长度后从头开始。