使用
定义
1 | private static ThreadLocal<String> CHARSET = new ThreadLocal<String>() { |
或者1
private static ThreadLocal<String> CHARSET = ThreadLocal.withInitial(() -> "utf-8");
销毁
1 | CHARSET.remove(); |
原理
- 一个线程Thread包含一个ThreadLocalMap变量
- 一个ThreadLocal包含一个ThreadLocalMap内部类
- 一个ThreadLocalMap包含一个Entry内部类
- 一个ThreadLocalMap的key为ThreadLocal对象
- 一个ThreadLocalMap的value为Entry的数组
初始化
1 | private T setInitialValue() { |
setInitialValue为ThreadLocal方法,负责
- 初始化线程变量
- 初始化线程变量值
1 | public class Thread implements Runnable { |
threadLocals属于当前线程,负责
- 记录线程变量
- 保持多线程隔离
1
2
3
4
5
6
7
8
9
10
11public class ThreadLocal<T> {
void createMap(Thread t, T firstValue) {
//初始化值到map中,this为ThreadLocal对象
//threadLocals为线程变量
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap getMap(Thread t) {
//获取本线程变量map
return t.threadLocals;
}
}
createMap为ThreadLocal方法,负责创建线程变量map
1 | public class ThreadLocal<T> { |
ThreadLocalMap为ThreadLocal静态类,key为ThreadLocal对象,提供
- 当前线程内,所有变量和值得map
- 设置索引位置,设置resize阈值
set
ThreadLocal方法1
2
3
4
5
6
7
8
9
10public void set(T value) {
//当前线程对象
Thread t = Thread.currentThread();
//获取线程内的变量map
ThreadLocalMap map = getMap(t);
if (map != null)
//赋值
map.set(this, value);
else
createMap(t, value);
赋值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
//取余
int i = key.threadLocalHashCode & (len-1);
//存在该索引值
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
//找到key
if (k == key) {
//替换
e.value = value;
return;
}
//k为null,即弱引用的垃圾回收,则清除旧值并替换设置值
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
//不存在则新建
tab[i] = new Entry(key, value);
//当前大小+1
int sz = ++size;
//清除弱引用无用数据并确定是否扩容
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
- 负责设置变量值
get
1 | public T get() { |
hash和索引计算
firstKey.threadLocalHashCode,获取线程变量hashcode1
2
3
4
5private final int threadLocalHashCode = nextHashCode();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
- 0x61c88647,斐波那契散列即黄金分割
- HASH_INCREMENT的0x61c88647对应的十进制为1640531527
- 0x61c88647与一个神奇的数字产生关系,就是 (Math.sqrt(5) - 1)/2。也就是传说中的黄金比例 0.618(0.618 只是一个粗略值),即0x61c88647 = 2^32 * 黄金分割比。
- 通过HASH_INCREMENT再借助一定的算法,就可以将哈希码能均匀的分布在2的N次方的数组里,保证了散列表的离散度,从而降低了冲突几率。
- 用0x61c88647作为魔数累加为每个ThreadLocal分配各自的ID也就是threadLocalHashCode再与2的幂取模,得到的结果分布很均匀。
- firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1)即求余