ThreadLocal源码分析:(三)remove()方法
2018-03-27 17:30
323 查看
在ThreadLocal的get(),set()的时候都会清除线程ThreadLocalMap里所有key为null的value。
而ThreadLocal的remove()方法会先将Entry中对key的弱引用断开,设置为null,然后再清除对应的key为null的value。
本文分析remove方法
ThreadLocal类的remove方法
直接调用ThreadLocalMap的remove方法。
代码1
ThreadLocalMap类的remove方法
找到准确的key对应的entry之后,调用Entry的clear方法,紧接着调用expungeStaleEntry,对key为null的entry进行清理。
代码2
Reference类的clear方法,Entry是Reference的子类
很简单,就是把reference指向null,也就是将该entry的key指向null。方便后面对该entry进行清理。
代码3
ThreadLocal.ThreadLocalMap类的expungeStaleEntry方法
expungeStaleEntry方法不止清理了staleSlot位置上的entry,还把staleSlot之后的key为null的entry都清理了,并且顺带将一些有哈希冲突的entry给填充回可用的index中。
到这里ThreadLocal的remove方法也分析完了。remove方法的关键就在于主动断开entry的key的引用链接,这样在后续的expungeStaleEntry方法中,就会将这种key为null的entry给设置为null,方便GC对内存进行回收。
ThreadLocal的set,get和remove方法看下来,除了正常的功能之外,就是多了对key为null的entry的清理工作,方便GC回收这部分占用的内存。expungeStaleEntry就是最核心的清理方法,这也是ThreadLocalMap的一种防范机制,因为ThreadLocalMap的生命周期和线程是一样长的,不采取这种防范机制,是会造成内存泄漏的。如果多定义了几个ThreadLocal对象,并且线程都将占用内存比较大的对象给放到对应的线程中,可能就会造成OOM异常了。
本文也是因为在网上看到有分析使用ThreadLocal造成的OOM异常,所以才深入看看ThreadLocal的源码。JDK源码写的确实很有水平,层次分明,功能封装粒度合适,自己看看还是感觉很通透的。
系列文章链接:
ThreadLocal源码分析:(一)set(T value)方法
ThreadLocal源码分析:(二)get()方法
ThreadLocal源码分析:(三)remove()方法
而ThreadLocal的remove()方法会先将Entry中对key的弱引用断开,设置为null,然后再清除对应的key为null的value。
本文分析remove方法
ThreadLocal类的remove方法
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); // 调用ThreadLocalMap的remove方法,见代码1 }
直接调用ThreadLocalMap的remove方法。
代码1
ThreadLocalMap类的remove方法
private void remove(ThreadLocal<?> key) { 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)]) { if (e.get() == key) { // 考虑到可能的哈希冲突,一定要准确找到此key对应的entry e.clear(); // 调用Entry的clear方法,见代码2 expungeStaleEntry(i); // 又是这个清除key为null的entry的方法,见代码3 return; } } }
找到准确的key对应的entry之后,调用Entry的clear方法,紧接着调用expungeStaleEntry,对key为null的entry进行清理。
代码2
Reference类的clear方法,Entry是Reference的子类
public void clear() { this.referent = null; }
很简单,就是把reference指向null,也就是将该entry的key指向null。方便后面对该entry进行清理。
代码3
ThreadLocal.ThreadLocalMap类的expungeStaleEntry方法
private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; // expunge entry at staleSlot tab[staleSlot].value = null; tab[staleSlot] = null; size--; // 以上代码,将entry的value赋值为null,这样方便GC时将真正value占用的内存给释放出来;将entry赋值为null,size减1,这样这个slot就又可以重新存放新的entry了 // Rehash until we encounter null Entry e; int i; for (i = nextIndex(staleSlot, len); // 从staleSlot后一个index开始向后遍历,直到遇到为null的entry (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get(); if (k == null) { // 如果entry的key为null,则清除掉该entry e.value = null; tab[i] = null; size--; } else { int h = k.threadLocalHashCode & (len - 1); if (h != i) { // key的hash值不等于目前的index,说明该entry是因为有哈希冲突导致向后移动到当前index位置的 tab[i] = null; // Unlike Knuth 6.4 Algorithm R, we must scan until // null because multiple entries could have been stale. while (tab[h] != null) // 对该entry,重新进行hash并解决冲突 h = nextIndex(h, len); tab[h] = e; } } } return i; // 返回经过整理后的,位于staleSlot位置后的第一个为null的entry的index值 }
expungeStaleEntry方法不止清理了staleSlot位置上的entry,还把staleSlot之后的key为null的entry都清理了,并且顺带将一些有哈希冲突的entry给填充回可用的index中。
到这里ThreadLocal的remove方法也分析完了。remove方法的关键就在于主动断开entry的key的引用链接,这样在后续的expungeStaleEntry方法中,就会将这种key为null的entry给设置为null,方便GC对内存进行回收。
ThreadLocal的set,get和remove方法看下来,除了正常的功能之外,就是多了对key为null的entry的清理工作,方便GC回收这部分占用的内存。expungeStaleEntry就是最核心的清理方法,这也是ThreadLocalMap的一种防范机制,因为ThreadLocalMap的生命周期和线程是一样长的,不采取这种防范机制,是会造成内存泄漏的。如果多定义了几个ThreadLocal对象,并且线程都将占用内存比较大的对象给放到对应的线程中,可能就会造成OOM异常了。
本文也是因为在网上看到有分析使用ThreadLocal造成的OOM异常,所以才深入看看ThreadLocal的源码。JDK源码写的确实很有水平,层次分明,功能封装粒度合适,自己看看还是感觉很通透的。
系列文章链接:
ThreadLocal源码分析:(一)set(T value)方法
ThreadLocal源码分析:(二)get()方法
ThreadLocal源码分析:(三)remove()方法
相关文章推荐
- jQuery源码分析之jQuery.event.remove方法
- jQuery源码分析之remove和detach方法的区别
- jQuery源码分析之removeAttr方法和attr方法
- jQuery源码解读之removeClass()方法分析
- ThreadLocal源码分析:(二)get()方法
- jQuery源码分析之empty和remove方法四问
- jQuery源码解读之removeClass()方法分析
- jQuery源码解读之removeAttr()方法分析
- jQuery源码解读之removeAttr()方法分析
- 【Android】ArrayList通过remove方法删除元素对象源码分析
- jquery原型方法map的使用和源码分析
- 【转】Android笔记:触摸事件的分析与总结----Touch事件分发方法dispatchTouchEvent()源码分析
- Linux内核源码分析方法
- dubbo源码分析10——服务暴露1_export()方法分析
- 从源码来分析ThreadLocal、Message、Handler、Looper、MessageQueue
- [Java多线程]-ThreadLocal源码及原理的深入分析
- Qt多线程和GUI界面假死(分析QThread::exec函数的源码,旧的QMutexLocker方法其实很好用,挡住别人进入抢占资源)
- nginx源码分析(5)-方法(2)
- jQuery源码分析之parseHTML方法
- 分析 源码 的一些方法