ThreadLocal源码解析(1)

大家想必平时在工作中都或多或少的用到过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);
}
  • 方法传递的参数firstKeyfirstValue分别作为初始化创建的第一个key和第一个value
table = new Entry[INITIAL_CAPACITY];
  • table是维护的一个Entry类型的数组, 作为存储的每个元素的表示, 初始化容量是INITIAL_CAPACITY, 默认是16, 后面会单独介绍Entry这个类…
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
  • 进行hash值计算映射
  • 然后是赋值和初始化size值
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这个类的相关知识

你可能感兴趣的:(并发编程,java)