ThreadLocal中的一些点
程序员文章站
2022-03-26 15:47:04
ThreadLocalMap是ThreadLocal中的一个静态内部类ThreadLocalMap中有一个Entry数组,存放着value可能导致内存泄漏因为,ThreadLocalMap中的Entry中的key也就是传进来的ThreadLocal是弱引用,也就说ThreadLocal对象分别有一个强引用一个弱引用,如果ThreadLcoal的强引用失去后,只剩下弱引用,n那就在下次垃圾回收时key就会被回收,value不会被回收,就会导致Entry数组的某一位,e.get() == nulle.v....
ThreadLocalMap是ThreadLocal中的一个静态内部类
ThreadLocalMap中有一个Entry数组,存放着value
内存泄漏
可能导致内存泄漏因为,ThreadLocalMap中的Entry中的key也就是传进来的ThreadLocal是弱引用,也就说ThreadLocal对象分别有一个强引用一个弱引用,如果ThreadLcoal的强引用失去后,只剩下弱引用,n那就在下次垃圾回收时key就会被回收,value不会被回收,就会导致Entry数组的某一位,e.get() == null
e.value != null ,导致内存泄漏。
ThreadLocalMap本身有一些预防措施,在set和get的时候会清除那些内存泄漏的地方
我们正确使用时,在用完ThreadLocal的时候remove一下,就行了
ThreadLocal 主要是用他的hashcode做key
这个hash数字找的太精彩了,每次求新的hash码只需要累加就行了,最后取模的时候就会很分散!!!!
有同学注意到,这样不会爆int吗?答案:会 正是因为会爆int所以均匀,即使爆了int,数也不是随机来的,重新从负数开始
网上一个测试。
每个线程都有一个ThreadLocalMap 的实例对象 这个对象是以 threadLocalHashCode作为key,value作为值的,一个线程可以有很多ThreadLocal;
分析一下set过程
ThreadLocal中的set
public void set(T value) {
Thread t = Thread.currentThread();//得到现在是哪个线程
ThreadLocalMap map = getMap(t);//得到该线程的ThreadLocalMap实例
if (map != null) { //如果不是第一次初始化
map.set(this, value);//调用ThreadLocalMap中的HashMap
} else { //如果是第一次初始化
createMap(t, value);
}
}
ThreadLocalMap中的set
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);//获得在table中的位置
//冲突顺延法
for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
//如果以前存在就更新
if (k == key) {
e.value = value;
return;
}
//找到空位就new
if (k == null) {
//replaceStaleEntry间接调用-整理那些内存泄漏的位置
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
//整理那些内存泄漏的位置
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
//整理那些内存泄漏的位置
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;
}
分析一下get
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
//调用ThreadLocalMap的getEctry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
//通过hash定位,看看是不是null,不是null看看是不是当前ThreadLocal,如果不是顺序后延查找
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
//getEntryAfterMiss间接调用-整理那些内存泄漏的位置
return getEntryAfterMiss(key, i, e);
}
本文地址:https://blog.csdn.net/weixin_43912833/article/details/113926727