ThreadLocal 源码分析
ThreadLocal线程局部变量,使得各线程能够保持各自独立的一份对象。通常被定义为类的静态类变量。
ThreadLocal类本身定义了有get(), set(), remove()和initialValue()方法。前面三个方法是public的,initialValue()是protected的,主要用于我们在定义ThreadLocal对象的时候根据需要来重写。这样我们初始化这么一个对象在里面设置它的初始值时就用到这个方法。ThreadLocal变量因为本身定位为要被多个线程来访问,它通常被定义为static变量。
ThreadLocal API
方法
T get()
返回此线程局部变量的当前线程副本中的值。
protected T initialValue()
返回此线程局部变量的当前线程的“初始值”。
void remove()
移除此线程局部变量当前线程的值。
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。
源码分析
ThreadLocal有一个ThreadLocalMap静态内部类,ThreadLocalMap的实例是java.lang.Thread的成员变量,每个线程有唯一的一个threadLocalMap。这个map以ThreadLocal对象为key,实际存储内容为值。对ThreadLocal的操作,实际委托给当前Thread,每个Thread都会有自己独立的ThreadLocalMap实例。ThreadLocalMap使用线性探测法解决hash冲突。
ThreadLocal
T get()
返回此线程局部变量的当前线程副本中的值。
|
|
protected T initialValue()
返回此线程局部变量的当前线程的“初始值”。
|
|
void remove()
移除此线程局部变量当前线程的值。
|
|
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。
|
|
|
|
ThreadLocalMap
|
|
ThreadLocalMap的定位方法:
int index = threadLocalHashCode & (len - 1)
HASH_INCREMENT = 0x61c88647
每个ThreadLocal中的threadLocalHashCode都是HASH_INCREMENT的倍数,0x61c88647这个数字&上2的n次方-1的数字,hash分布十分的均匀。
|
|
测试hash分布
|
|
输出:
0
7
14
21
28
3
10
17
24
31
6
13
20
27
2
9
16
23
30
5
12
19
26
1
8
15
22
29
4
11
18
25
可以看到几乎没有发生hash冲突。
ThreadLocal使用方式
|
|
使用建议
- ThreadLocal应定义为静态成员变量。
- 能通过传值传递的参数,不要通过ThreadLocal存储,以免造成ThreadLocal的滥用。
- 在线程池的情况下,在ThreadLocal业务周期处理完成时,最好显式的调用remove()方法。