ThreadLocal的源码解读
理解ThreadLocal内部存储结构
属性解释
//这个是ThreadLocal对象的哈希值,通过调用nextHashCode()方法获取
private final int threadLocalHashCode = nextHashCode();
//存储哈希值的变量,属性是AtomicInteger原子类,是一个静态变量
private static AtomicInteger nextHashCode = new AtomicInteger();
// 每一次nextHashCode增加的数值大小,表示哈希值的增量
// 每创建一个ThreadLocal对象,nextHashCode就会增长HASH_INCREMENT
// HASH_INCREMENT是一个黄金分割数,哈希增量为这个值
// 可以使Map中的数分布均匀
private static final int HASH_INCREMENT = 0x61c88647;
//获取hash值
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
//初始化一个起始value,,一般这个方法都是会重写的
protected T initialValue() {
return null;
}
get()方法分析
public T get() {
//Thread.currentThread()是一个本地静态的native方法,返回一个Thread对象
Thread t = Thread.currentThread();
//获取当前线程内部的ThreadLocalMap,一开始默认为null,直接走return的setInitialValue()
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
//初始化一个ThreadLocalMap,放进去一个null值
private T setInitialValue() {
T value = initialValue();//返回一个null值
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//返回的map 是null,则创建一个map放进去一个null值
createMap(t, value);
return value;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
set(T value)方法分析
//参考上面的setInitialValue方法,逻辑基本一样
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap源码分析
成员变量
//ThreadLocalMap内部是一个Entry数组,INITIAL_CAPACITY就是这个Entry数组的容量大小
private static final int INITIAL_CAPACITY = 16;
//用来存放数据的entry数组
private Entry[] table;
//当前数组的大小
private int size = 0;
//扩容阈值,初始值为 len * 2 / 3
private int threshold; // Default to 0
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
构造方法
线程的ThreadLocalMap是延迟初始化的,只有当线程第一次存储key-value键值对时才会进行初始化。
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
//创建一个初始大小为16的entry数组
table = new Entry[INITIAL_CAPACITY];
//计算第一个值的hashcode
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
//将值放入table中
table[i] = new Entry(firstKey, firstValue);
size = 1;
//初始化阈值
setThreshold(INITIAL_CAPACITY);
}
这里不小心看错了,下面这个方法不是ThreadLocalMap构造方法,这个是用来父子线程传递数据用的方法
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
Entry方法分析
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
引申出来的几个重要知识点
-
Java的四种对象引用级别
-
为什么ThreadLocal设计成弱引用
-
什么是对象可达,对象不可达
简单点就是对象为null就是不可达
-
gc垃圾回收,逐步接触(需要系统的学习)
-
堆栈数据怎么分析,使用什么工具,参数的含义
测试头像