车驰夜幕|面试时被问到ThreadLocal别慌,你要的答案都在这里( 四 )
replaceStaleEntry方法也会调用expungeStaleEntry方法 。
再看看setInitialValue方法中的createMap方法
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}
代码很简单 , 就是new了一个ThreadLocalMap对象 。
好了 , 到这来get() 和 initialValue() 方法介绍完了 。
下面介绍set(T value) 方法
public void set(T value) {//获取当前线程 , 都是一样的套路Thread t = Thread.currentThread();//根据当前线程获取当中的ThreadLocalMapThreadLocalMap map = getMap(t);//ThreadLocalMap不为空 , 则调用之前介绍过的ThreadLocalMap的set方法if (map != null)map.set(this, value);else//如果ThreadLocalMap为空 , 则创建一个对象 , 之前也介绍过createMap(t, value);}
so easy
最后 , 看看remove()方法
public void remove() {//还是那个套路 , 不过简化了一下//先获取当前线程 , 再获取线程中的ThreadLocalMap对象ThreadLocalMap m = getMap(Thread.currentThread());//如果ThreadLocalMap不为空if (m != null)//删除数据m.remove(this); }
这个方法的关键就在于ThreadLocalMap类的remove方法
private void remove(ThreadLocal> key) {//将table数组赋值给新数组tabEntry[] tab = table;//获取数组长度int len = tab.length;//跟之前一样计算数组中的下表int i = key.threadLocalHashCode//循环变量从下表i之后不为空的entryfor (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {//如果可以获取到threadLocal并且值等于keyif (e.get() == key) {//清空引用e.clear();//处理threadLocal为空但是value不为空的entryexpungeStaleEntry(i);return;}}}
其中的clear方法 , 也很简单 , 只是把引用设置为null , 即清空引用
public void clear() {this.referent = null;}
我们可以看到get()、set(T value) 和 remove()方法 , 都会调用expungeStaleEntry方法 , 我们接下来重点看一下expungeStaleEntry方法
private int expungeStaleEntry(int staleSlot) {Entry[] tab = table;int len = tab.length;//将位置staleSlot对应的entry中的value设置为null , 有助于垃圾回收tab[staleSlot].value = http://kandian.youth.cn/index/null;//将位置staleSlot对应的entry设置为null , 有助于垃圾回收tab[staleSlot] = null;//数组大小-1size--;Entry e;int i;//变量staleSlot之后entry不为空的数据for (i = nextIndex(staleSlot, len);(e = tab[i]) != null;i = nextIndex(i, len)) {//获取当前位置的entry中对应的threadLocalThreadLocal> k = e.get();//threadLocal为空 , 说明是脏数据if (k == null) {//value设置为null , 有助于垃圾回收e.value = http://kandian.youth.cn/index/null;//当前位置的entry设置为nulltab[i] = null;//数组大小-1size--;} else {//重新计算位置int h = k.threadLocalHashCode//如果h和i不相等 , 说明存在hash冲突//现在它前面的脏Entry被清理//该Entry需要向前移动 , 防止下次get()或set()的时候//再次因散列冲突而查找到null值if (h != i) {tab[i] = null;while (tab[h] != null)h = nextIndex(h, len);tab[h] = e;}}}return i;}
该方法首先清除当前位置的脏Entry , 然后向后遍历直到table[i]==null 。 在遍历的过程中如果再次遇到脏Entry就会清理 。如果没有遇到就会重新变量当前遇到的Entry , 如果重新散列得到的下标h与当前下标i不一致 , 说明该Entry被放入Entry数组的时候发生了散列冲突(其位置通过再散列被向后偏移了) , 现在其前面的脏Entry已经被清除 , 所以当前Entry应该向前移动 , 补上空位置 。 否则下次调用set()或get()方法查找该Entry的时候会查找到位于其之前的null值 。
- 小鹰说科技|美军警告:别想分割封锁我们,美火速增兵叙利亚!大批装甲车驰援
- 通过率只有3%的面试还难,湖畔大学的学员答辩都在讨论什么?
- 上观新闻|夜幕下的南京路步行街东拓段,灯光璀璨,景色更加迷人
- 柚子在野区|【当当与您早知道】月亮不“孤单”
- 车驰夜幕|美国GPS卫星精度0.4米,俄卫星的精度1.2米,中国北斗呢?
- 车驰夜幕|联合国向你发来活动邀请:与全球尖端人士探讨关注自然的真谛
- 陕西省教育厅|定了!2020年教师资格证笔试、面试时间公布
- 车驰夜幕|简单聊聊处理器的核显
- 模范爸爸|「干货满满」1.5w字初中级前端面试复习总结
- 澎湃新闻|非全日制研究生通过面试后被取消资格?官方:前期审核失误