大家想必平时在工作中都或多或少的用到过ThreadLocal
, 应用场景也是多种多样, 今天我们来看一下源码大致是怎么实现的
从set
方法开始, set
方法的作用就是设置一个线程变量, 让ThreadLocal
管辖
public void set(T value) {
Thread t = Thread.currentThread(); // 获取当前线程
ThreadLocalMap map = getMap(t); // 通过当前线程获取ThreadLocalMap
// 下面就是一些非空的判断, 不是重点
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
接下来, 我们看看是怎么通过当前线程获取ThreadLocalMap
的, ThreadLocalMap
又是什么?
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
首先从getMap
的源码可以看到, 获取的直接是当前线程的一个threadLocals
变量, 也就是说对于每个线程都有一个对应的threadLocals
变量, 这就是实现线程隔离的本质
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null; // Thread类中的threadLocals
至此, 我们知道了ThreadLocal
的实现是通过每个线程自己的ThreadLocalMap
, 我们继续看一下ThreadLocalMap
这个类的实现
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
首先看一下其中一个构造方法, 这个构造方法调用可以追溯到ThreadLocal#createMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
firstKey
和firstValue
分别作为初始化创建的第一个key和第一个valuetable = new Entry[INITIAL_CAPACITY];
Entry
类型的数组, 作为存储的每个元素的表示, 初始化容量是INITIAL_CAPACITY
, 默认是16, 后面会单独介绍Entry
这个类…int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
setThreshold(INITIAL_CAPACITY);
/**
* The next size value at which to resize.
* 也就是说如果Entry数组的元素数达到数组长度的2/3, 触发扩容
*/
private int threshold; // Default to 0
/**
* Set the resize threshold to maintain at worst a 2/3 load factor.
* 设置resize threshold以在最坏的情况下保持2/3的负载系数。
*/
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
setThreshold()
方法的作用就是设置threshold
这个的值, 这个值就是下一次扩容的阈值先分析到这里, 下一篇我们分析一下Entry
这个类的相关知识