ThreadLocal相关使用
简介
ThreadLocal类用来提供线程内部的局部变量,这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLoca实例通常来说都是private static类型的,用于关联线程和线程上下文。
三个方面讨论ThreadLocal:
- 线程并发:如果是单线程,也就i用不到ThreadLocal来存储独立于其他线程的变量了,只有在多线程并发情况下,ThreadLocal用处得以体现。
- 传递数据:我们可以通过ThreadLocal中存储变量在线程中的不同组件之间传递数据。
- 线程隔离:指的是不同线程的ThreadLocal是相互隔离,相互不影响的。
ThreadLocal常用方法
- ThreadLocal()方法:创建ThreadLocal对象。
- set() 设置当前线程绑定的局部变量
- get() 获取当前线程绑定的局部变量
- 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移除或者线程执行借宿移除。
最终解决方案
避免内存泄露的两种方式:
- 使用完ThreadLocal,调用remove方法删除对应的entry
- 使用完ThreadLocal ,当前线程也随即结束。
ThreadLocalMap存储的时候Map冲突
底层采用的解决方法:线性探测法,当从图的时候查看下一个位置是否满足要求,超过map的长度后从头开始。