ThreadLocal 源码分析

91 阅读1分钟

数据结构

ThreadLocal.png

set

public void set(T value) {
    Thread t = Thread.currentThread();
    // 获取 ThreadLocalMap 对象
    ThreadLocalMap map = getMap(t);
    if (map != null)
        // 存在设置值
        map.set(this, value);
    else
        // 把线程传入进来 value
        createMap(t, value);
}

set(ThreadLocal<?> key, Object value) 存在冲突的时候如何存值?

private 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)] ) 
    {
         //获取操作的对象 就是那个线程把value 赛进来的
        // 就是ThreadLocal
        ThreadLocal<?> k = e.get();
        if (k == key) 
        {
            // 如果等于 替换
            e.value = value;
            return;
        }
        // 没有咋办
        if (k == null) {
            replaceStaleEntry(key, value, i);
            return;
        }
    }

     // 创建节点 赋值
    tab[i] = new Entry(key, value);
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        // 扩容
        rehash();
}

createMap

/**
  t 线程  firstValue 保存的数据
**/
void createMap(Thread t, T firstValue) 
{
    // 创建对象ThreadLocalMap
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocalMap 创建对象

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) 
{
    //setp1 创建了entry 对象数组
    table = new Entry[INITIAL_CAPACITY];
    // step2 计算数组下标的位置
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    // 数组元素赋值 firstKey 创建的threadLocal 对象 firstValue 设置的值
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    // 设置数组的阈值
    setThreshold(INITIAL_CAPACITY);
}

链地址法和开放地址法的优缺点

采用开放地址法解决冲突