基于JDK1.8
使用场景
1、在当前Thread中存取Looper
2、储存本线程特有的数据
基本原理
1、在Thread.java中设置了内部变量mThreadLocal,从而实现了数据同线程的绑定
2、ThreadLocalMap本质是哈希表,内部用Entry[]进行存取,储存节点是Entry(ThreadLocal key, Object value),通过key的哈希结合数组长度计算存取位置,其中key的类型是ThreadLocal。
//数组存取数据位置
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
知识点
1、如何确定储存位置
2、如何扩容,阈值是多少
3、如何解决hash冲突
4、调用set()后内部如何执行
5、调用get()后内部如何执行
源码分析
1、threadLocalMap中同hashMap一样,大小设为了2的幂次,默认16,这样可以用“&”运算代替“%”,计算位置如下
//数组存取数据位置 firstKey是ThreadLocal类型
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
上面threadLocalHashCode是当前ThreadLocal的hashCode,但它不是对当前threadLocal直接计算hash,而是直接增加一个固定值(Int值上限*黄金分割比例)
private final int threadLocalHashCode = nextHashCode();
/**
* The next hash code to be given out. Updated atomically. Starts at
* zero.
*/
private static AtomicInteger nextHashCode = new AtomicInteger();
/**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647;
/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
2、阈值为当前数组长度的2/3 * 3/4 = 1/2。扩容时双倍扩容,首先遍历旧数组,如果key为null直接设置value为null,否则重新计算存储位置;如果此位置为null则直接赋值,否则使用线性探索法依次往后寻找空位置存储(线性探测法)。
/**
* Set the resize threshold to maintain at worst a 2/3 load factor.
*/
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
private void rehash() {
expungeStaleEntries();
// Use lower threshold for doubling to avoid hysteresis
if (size >= threshold - threshold / 4)
resize();
}
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
int count = 0;
for (int j = 0; j < oldLen; ++j) {
Entry e = oldTab[j];
if (e != null) {
ThreadLocal<?> k = e.get();
if (k == null) {
e.value = null; // Help the GC
} else {
int h = k.threadLocalHashCode & (newLen - 1);
while (newTab[h] != null)
h = nextIndex(h, newLen);
newTab[h] = e;
count++;
}
}
}
setThreshold(newLen);
size = count;
table = newTab;
}
3、未完待续,有空就写写
2021年11月 younger
网友评论