ThreadLocal源码分析学习

set方法

当创建一个ThreadLocal对象执行set方法时,首先会获取到当前线程的threadLocalMaps.

public void set(T value) {
    Thread t = Thread.currentThread();
    // 获得当前线程的ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        map.set(this, value);
    } else {
        createMap(t, value);
    }
}

调用map.set()

// 设置threadLocalMap中Entry[] 的值
插入时分为4种情况
1. 待插入的下标,是空位置直接插入。
2. 待插入的下标,不为空,key 相同,直接更新
3. 待插入的下标,不为空,key 不相同,开放寻址
4. 不为空,key 不相同,碰到过期key。其实情况4,遇到的是弱引用发生GC时,产生的情况。碰到这种情况,ThreadLocal 会进行探测清理过期key

每次插入之后会进行一次探测性清理来判断是否满足扩容的条件也就是

if (!cleanSomeSlots(i, sz) && sz >= threshold)
       rehash();

cleanSomeSlots代码

说白了就是判断entry中是否有需要清楚的对象。

private boolean cleanSomeSlots(int i, int n) {
    boolean removed = false;
    Entry[] tab = table;
    int len = tab.length;
    do {
        i = nextIndex(i, len);
        Entry e = tab[i];
        if (e != null && e.get() == null) {
            n = len;
            removed = true;
            i = expungeStaleEntry(i);
        }
    } while ( (n >>>= 1) != 0);
    return removed;
}

expungeStaleEntry

就是进行清理。

resize()代码

rehash首先进行探测性清理然后进行resize()操作,resize判断当前的数组是否需要扩容,如果需要将Entry的容量扩展为之前的2倍

private void rehash() {
   expungeStaleEntries();

   // Use lower threshold for doubling to avoid hysteresis
   if (size >= threshold - threshold / 4)
       resize();
}

get方法

首先就是获取当前线程对应的map然后获取当前threadLocal对象.

public T get() {
   Thread t = Thread.currentThread();
   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();
}

getEntry方法

private Entry getEntry(ThreadLocal<?> key) {
   int i = key.threadLocalHashCode & (table.length - 1);
   Entry e = table[i];
   if (e != null && e.get() == key)
       return e;
   else
       return getEntryAfterMiss(key, i, e);
}

getEntryAfterMiss方法

会进行判断当前元素是否被GC回收了,如果k == null 进行清楚.

private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
    Entry[] tab = table;
    int len = tab.length;
    while (e != null) {
        ThreadLocal<?> k = e.get();
        if (k == key)
            return e;
        if (k == null)
            expungeStaleEntry(i);
        else
            i = nextIndex(i, len);
        e = tab[i];
    }
    return null;
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值