标签:warning code 初始化 正在执行 执行 atomic object incr 阈值
1 怎么new出来一个ThreadLocal
1 private ThreadLocal<Integer> num=new ThreadLocal<Integer>(){ 2 public Integer initialValue(){ 3 return 0; 4 } 5 };
2 实现 initialValue 有什么用
ThreadLocal在第一个执行get,set方法前是null,如果第一次执行get会返回initialValue的返回值,同时初始化ThreadLocalMap
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(); }
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
3 ThreadLocalMap的数据结构
Entry数组,Entry是key,value结构,keyshiThreadLocal对象的引用,value就是业务定义的value
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } private static final int INITIAL_CAPACITY = 16; private Entry[] table;
4 Entry的key为啥是弱引用
这样是为了不影响原ThreadLocal对象的回收,如果用户对ThreadLocal对象赋值为null,该ThreadLocal对象是有可能被回收的,如果ThreadLocalMap中是强引用会导致无法回收
5 ThreadLocal的hash值怎么算的
private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode = new AtomicInteger(); private static final int HASH_INCREMENT = 0x61c88647; private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }
这段代码怎么理解呢,注意这个 threadLocalHashCode 是final的,也就是说new出来后就固定了
如果一个类中定义了两个ThreadLocal变量,那么第一个hash值是0,第二个hash值就是0x61c88647,一次类推。这两个ThreadLocal对象都会作为key,存入当前正在执行这段代码的线程的ThreadLocalMap里。
6 扩容阈值是多少,到达了该阈值一定会扩容吗
private void setThreshold(int len) { threshold = len * 2 / 3; }
不会,此时会进行全表扫描一次,清空失效key的操作,比如ThreadLocal对象被垃圾回收了,弱引用的get返回null。如果清理过后,存活的数量达到阈值的四分之三此时扩容
待更新源码
7 扩容算法
长度扩大为之前的两倍,对之前的数组里的元素进行迁移,然后重新计算扩容阈值
待更新源码
8 get的逻辑
get的时候回根据hash值,对size取模计算出来index,此时分为两种情况
1 有,还是自己,那就返回
2 有,但是不是自己,就是说发生了碰撞。此时要对下标+1进行查找,但是在查找的过程中还会对已经过期的entry进行清理
从当前的下标开始迭代,查找那些key是null的entry,把这个entry = null,遍历的条件是遇到entry是null
如果碰到没有失效的entry,计算该entry当前的位置是否是他应该的位置(就是不发生碰撞的位置),如果是则放过,
如果发生过冲突,对这个正常数据重新执行一次摆放。
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; }
expungeStaleEntry(i)我这里就不贴代码了,说明下执行过程
1 把i这个位置上的entry 的 key和value都置为null
2 从i的下一个位置开始循环,循环的条件是遍历到的entry不是null,同时下标会加一
3 对每个entry进行重新摆放
从这个while循环可以看出,如果在查找过程中,如果还没找到符合的entry,就遇到了null的entry,那么循环直接结束返回null
9 set的流程
按照hash值计算下标的位置,
1 该位置为null,最简单的情况,直接放上去
2 如果不是null,但是key相同,更value
3 如果不是null,但是key不同,下标加一继续找合适的位置
4 如果碰到过期的数据,以当前的下标的下一个位置开始向后查找直到遇到了null或者key相等停止,如果key相等那没啥说的,替换掉旧的value,然后再和过期的位置互换下,
如果是null,new 一个 Entry,把这个Entry直接放到失效的节点上,直接抹杀失效节点
另外还有启发式数据清理的过程
标签:warning code 初始化 正在执行 执行 atomic object incr 阈值
原文地址:https://www.cnblogs.com/juniorMa/p/13961432.html