关于ThreadLocal介绍
ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。
作用
提供线程内的局部变量,不同的线程之间不会相互干扰实现线程的隔离,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。
常用方法
ThreadLocal类与synchronized关键字
ThreadLocal和synchronized都可以实现多线程之间的隔离问题,但是synchronized关键字对多线程并发并不及ThreadLocal。
synchronized原理是采用同步机制,使用“以时间换空间”的方式。只提供一份变量让不同的线程排队访问。侧重于多线程之间的资源访问。
ThreadLocal原理是采用“以空间换时间”的实现方式,为每一个线程都提供一份变量的副本,从而实现同时访问而不互相干扰。侧重于多个线程之间的数据互相隔离。
使用ThreadLocal方案解决并发问题的好处
- 传递数据 : 保存每个线程绑定的数据,在需要的地方可以直接获取, 避免参数直接传递带来的代码耦合问题
- 线程隔离 : 各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失
ThreadLocal的内部结构
在JDK8中 ThreadLocal的设计是:每个Thread维护一个ThreadLocalMap,这个Map的key是ThreadLocal实例本身,value才是真正要存储的值Object。
具体的过程是这样的:
(1) 每个Thread线程内部都有一个Map (ThreadLocalMap)
(2) Map里面存储ThreadLocal对象(key)和线程的变量副本(value)
(3)Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。
(4)对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了副本的隔离,互不干扰。
这样设计的好处:
(1) 这样设计之后每个Map存储的Entry数量就会变少。因为之前的存储数量由Thread的数量决定,现在是由ThreadLocal的数量决定。在实际运用当中,往往ThreadLocal的数量要少于Thread的数量。
(2) 当Thread销毁之后,对应的ThreadLocalMap也会随之销毁,能减少内存的使用。
在项目中使用ThreadLocal的步骤
- 创建ThreadLocal的工具类。
- 在类中创建ThreadLocal静态对象。
private final static ThreadLocal<需要添加的对象类型> THREAD_LOCAL = new ThreadLocal<>();
- 在工具类中创建三个方法,分别实现ThreadLocal的三个核心方法。