threadlocal定义:每个线程有自己的数据 其他的线程拿不到
每个线程本身有一个threadlocals属性(类型是ThreadLocalMap),map中存储的entry的key是当前线程的threadlocal对象,value是自定义的值
ThreadLocalMap中的静态内部类Entry结构
static class Entry extends WeakReference>{
// 当前线程关联的threadlocal的value值Object value;
Entry(ThreadLocal>k, Object v) {super(k);
value=v;
}
}
注意entry的key是个弱引用,value是个强引用
那么为什么entry要设计成弱引用呢?
threadlocal对象被gc回收的时候 线程的threadlocalmap中相对应的entry的key变为null
可以区分哪些entry是过期的
注意:ThreadlocalMap类是静态内部类 是共享的数据
threadlocalmap放入元素的时候如果发生hash冲突 是不会转化为链表存储的,会向slot后查找可以存放的桶位,查找的时候也是这样
查找方法最核心的方法是:
1 private int expungeStaleEntry(intstaleSlot) { // 这个方法是用来优化查找 优化过期数据,目的是帮助过期数据让gc回收,让hash冲突的entry找到尽可能正确的位置
// 执行这个方法的时候说明查找的entry没找到并且key等于null staleSlot代表key为null的索引2 Entry[] tab =table;3 int len =tab.length;4
5 //expunge entry at staleSlot
6 tab[staleSlot].value = null;7 tab[staleSlot] = null;8 size--;9
10 //Rehash until we encounter null
11 Entry e;12 inti;13 for (i =nextIndex(staleSlot, len);14 (e = tab[i]) != null;15 i =nextIndex(i, len)) { //查找到entry不为null的索引16 ThreadLocal> k =e.get();17 if (k == null) { //key失效了18 e.value = null;19 tab[i] = null;20 size--;21 } else{22 //查到到的entry不是过期数据
23 int h = k.threadLocalHashCode & (len - 1);24 //并且就是位置不正确的entry 正确位置是h i是查找出来的entry的当前位置
25 if (h != i) {//h!=i说明位置发生了偏移了26 //将entry当前位置设置为null 也就是i设置为null
27 tab[i] = null;28
29 //Unlike Knuth 6.4 Algorithm R, we must scan until30 //null because multiple entries could have been stale.31 //如果h位置被占用了 就往后查找最靠近正确位置的index 找到就存入数据
32 while (tab[h] != null)33 h =nextIndex(h, len);34 tab[h] =e;35 }36 }37 }38 returni;39 }
threadlocal的entry数组中entry的size大于等于数组长度的3分之2进行rehash,扩容rehash前回先清除一下key失效的entry,如果清理过后entry的数量还大于等于threhold的4分之3
进行数组扩容并重新计算entry的下标