ThreadLocal与弱引用

ThreadLocal与弱引用

目录弱引用ThreadLocalThreadLocal与线程的关系ThreadLocalMap中的Entry

弱引用

什么是虚引用?简单的来说,下一次垃圾回收时,无论内存是否充足,都会被垃圾回收。那这玩意有什么用呢?看下面一段代码,相信对弱引用会有更好的理解:

WeakReference weakReference = new WeakReference<>(new byte[1024*1024*10]);

System.out.println(Objects.isNull(weakReference.get())); //输出false

weakReference = null;

System.gc();

System.out.println(Objects.isNull(weakReference.get())); //输出 true

ThreadLocal

threadLocal又是什么呢?随便百度,就能够得到大概的答案,threadLocal主要用于解决线程并发问题,将共享变量拷贝到一份到自己的线程,来避免并发修改以及竞态问题。那这其中有哪些坑呢?

ThreadLocal与线程的关系

看了ThreadLocal的基本API,可能会想当然的以为拷贝的数据就是存在ThreadLocal,那可就大错特错啦。事实上ThreadLocal只是起到一个桥梁的作用。真正的数据是和线程绑定的,存在Thread的ThreadLocalMap中。

ThreadLocal threadLocal = new ThreadLocal<>();

threadLocal.set(new Object());

// 业务

threadLocal.get();

在此具体的细节不在一一分析。

其实Thread内部内置了一个Map,Key为ThreadLocal,value为set的值,Entry本身为WeakReference的子类。

static class Entry extends WeakReference> {

Object value;

Entry(ThreadLocal k, Object v) {

super(k);

value = v;

}

}

线程中保存了一个ThreadLcoalMap 通过具体的ThreadLocal对象作为key,从ThreadLoacalMap中拿到Value

ThreadLocalMap中的Entry

问题又来了,为什么要用Entry要使用弱引用呢,其实大致大家都有一个答案?防止内存泄漏。那为什么弱引用可以防止泄露呢?一定可以避免吗?

我们看下下一段代码:

while (true){

ThreadLocal threadLocal = new ThreadLocal<>();

threadLocal.set(new byte[1024*1024*10]);

}

这段代码,跑一年也没啥事,原因就是弱引用的存在。因为每一次循环threadLocal的生命周期都会结束,根据可达性分析算法,当触发GC时,在过去循环产生的ThreadLcoal都将会被垃圾回收,有人可能会说了,ThreadLocalMap中不是还存在引用吗,巧了,那个是弱引用,不算数。此时Entry的Key也就是变成NULL,注意:

此时Entry还是存在的,只是你调用Entry#get()方法将会变成NULL。

每次调用set和get方法的时候,如果遇到key为NULL的Entry都会清理掉,这才能保证Entry被完整的回收。

那再看下面一段代码:

ThreadLocal [] ref= new ThreadLocal[10000];

while (true){

ThreadLocal threadLocal = new ThreadLocal<>();

threadLocal.set(new byte[1024*1024*10]);

ref[(int)i] = threadLocal;

++i;

}

在数组还没越界前,没多久就会OOM,因为threadlocal的强引用还在,会导致无法被回收。也就是说弱引用也并不是万能的,还是建议搭配remove方法一起食用

综上,就是笔者对于ThreadLocal的一些理解,若有不足,请多多指教

🎀 相关推荐

英雄联盟手游河道迅捷蟹刷新时间
microsoft365破解版

英雄联盟手游河道迅捷蟹刷新时间

📅 08-12 👀 5017
为什么库里投篮这么准?这就是原因!网友:一般人真做不到
宽带连接错误651解决方法?宽带连接错误651处理教程