聊聊ThreadLocal
ThreadLocal
维持线程封闭性的一种规范方法是使用ThreadLocal
,这个类能使线程中的某个值与保存值的对象关联起来。提供了get
和set
方法等访问接口和方法,这些方法为每个使用该变量的的线程都存有一份独立的副本,因此get
总是返回由当前执行线程在调用set
时设置的最新值。
官方解释如下:
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
就是说ThreadLocal
提供了线程本地变量,简单点说就是为每个线程都初始化了一份完全独立的变量副本供线程使用。ThreadLocal通常用private static
来修饰。当一个线程结束时,它所使用的所有ThreadLocal相对的实例副本都被回收。
常见用法
ThreadLocal
对象通常用于防止对可变的单实例变量(Singleton)或全局变量进行共享。
项目中经常会用到时间日期转换,所以新建DateFormatUtils
工具类,获取我们会有如下写法:
1 |
|
这种常见写法首先解决了应用反复创建SimpleDateFormat
对象所带来的系统损耗,但是又引来了一个非常重要的问题–并发问题。如果我们在并发环境下使用该方法:
1 |
|
系统运行情况如图所示:
由此我们发现,该方法在多线程环境下会有线程安全的问题。
解决并发问题的方式有很多,如synchronized
,这里使用ThreadLocal
来解决此问题。
DateFormatUtils
类改造如下:
1 |
|
运行成功!
源码阅读分析
ThreadLocal
结构
Thread
、ThreadLocal
、ThreadLocalMap
三者关系
可以发现每一个Thread
中都有一个ThreadLocalMap
。ThreadLocalMap
可以看作是一个数组,数组元素是自定义的Entry
类型,Entry
的key是ThreadLocal
类型,value是Object
类型。也就是说一个ThreadLocalMap
可以有多个ThreadLocal
。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!