https://mp.weixin.qq.com/s/S0IwbXadRgZ86fFLSFObVQ html
天天早上七点三十,准时推送干货若是说 ThreadLocal 的话,那确定就会涉及到内存泄漏,为啥嘞安全
由于 吧啦吧啦 ~多线程
它是为了解决对象不能被多线程共享访问的问题,经过 threadLocal.set() 方法将对象实例保存在每一个线程本身所拥有的 threadLocalMap 中,这样的话每一个线程都使用本身的对象实例,彼此不会影响从而达到了隔离的做用,这样就解决了对象在被共享访问时带来的线程安全问题app
啥意思呢?打个比方,如今公司全部人都要填写一个表格,可是只有一支笔,这个时候就只能上我的用完了以后,下我的才可使用,为了保证"笔"这个资源的可用性,只须要保证在接下来每一个人的获取顺序就能够了,这就是 lock 的做用,当这支笔被别人用的时候,我就加 lock ,你来了那就进入队列排队等待获取资源(非公平方式那就另外说了),这支笔用完以后就释放 lock ,而后按照顺序给下我的使用ide
可是彻底能够一我的一支笔对不对,这样的话,你填写你的表格,我填写个人表格,咱俩谁都不耽搁谁。这就是 ThreadLocal 在作的事情,由于每一个 Thread 都有一个副本,就不存在资源竞争,因此也就不须要加锁,这不就是拿空间去换了时间嘛源码分析
在开始以前,我们先把 Thread, ThreadLocal, ThreadLocalMap 的关系捋一捋:ui
在这里先给个解释,后面我们再详细分析:this
首先是由于 ThreadLocal 是基于 ThreadLocalMap 实现的,其中 ThreadLocalMap 的 Entry 继承了 WeakReference ,而 Entry 对象中的 key 使用了 WeakReference 封装,也就是说, Entry 中的 key 是一个弱引用类型,对于弱引用来讲,它只能存活到下次 GC 以前url
若是此时一个线程调用了 ThreadLocalMap 的 set 设置变量,当前的 ThreadLocalMap 就会新增一条记录,但因为发生了一次垃圾回收,这样就会形成一个结果: key 值被回收掉了,可是 value 值还在内存中,并且若是线程一直存在的话,那么它的 value 值就会一直存在spa
这样被垃圾回收掉的 key 就会一直存在一条引用链: Thread -> ThreadLocalMap -> Entry -> Value :
就是由于这条引用链的存在,就会致使若是 Thread 还在运行,那么 Entry 不会被回收,进而 value 也不会被回收掉,可是 Entry 里面的 key 值已经被回收掉了
这只是一个线程,若是再来一个线程,又来一个线程…多了以后就会形成内存泄漏
知道是怎么形成内存泄漏以后,接下来要作的事情就好说了,不是由于 value 值没有被回收掉因此才会致使内存泄露的嘛
那使用完 key 值以后,将 value 值经过 remove 方法 remove 掉,这样的话内存中就不会有 value 值了,也就防止了内存泄漏嘛
OK ,上面的内容讲完了,接下来一一来看
首先,你怎么知道 ThreadLocal 是基于 ThreadLocalMap 实现的呢?
从源码知道的~
在源码中可以看到下面这几行代码:
public class ThreadLocal<T> {
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;
}
}
}
}
代码中说的很清楚了,在 ThreadLocal 内部维护着 ThreadLocalMap ,而它的 Entry 则继承自 WeakReference 的 ThreadLocal<?> ,其中 Entry 的 k 为 ThreadLocal , v 为 Object ,在调用 super(k) 时就将 ThreadLocal 实例包装成了一个 WeakReference
强弱引用这块内容阿粉就直接放一个表格吧:
引用类型 | 功能特色 |
---|---|
强引用 ( Strong Reference ) | 被强引用关联的对象永远不会被垃圾回收器回收掉 |
软引用( Soft Reference ) | 软引用关联的对象,只有当系统将要发生内存溢出时,才会去回收软引用引用的对象 |
弱引用 ( Weak Reference ) | 只被弱引用关联的对象,只要发生垃圾收集事件,就会被回收 |
虚引用 ( Phantom Reference ) | 被虚引用关联的对象的惟一做用是能在这个对象被回收器回收时收到一个系统通知 |
从表格中应该可以看出来,弱引用的对象只要发生垃圾收集事件,就会被回收
因此弱引用的存活时间也就是下次 GC 以前了
在这里阿粉就有个问题想问问了:为何 ThreadLocal 采用弱引用,而不是强引用嘞?
在 ThreadLocalMap 上面有些注释,我在这里摘录一部分,或许能够从中窥探一二:
To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys
翻译一下就是:(虽然我英语不是很好
为了解决很是大且长期使用的问题,哈希表使用了弱引用的 key
假设,假设, ThreadLocal 使用的是强引用,会怎样呢?
若是是强引用的话,在表格中也可以看出来,被强引用关联的对象,永远都不会被垃圾回收器回收掉
若是引用的 ThreadLocal 对象被回收了,可是 ThreadLocalMap 还持有对 ThreadLocal 的强引用,若是没有 remove 的话, 在 GC 时进行可达性分析, ThreadLocal 依然可达,这样就不会对 ThreadLocal 进行回收,可是咱们指望的是引用的 ThreadLocal 对象被回收,这样不就达不到目的了嘛
使用弱引用的话,虽然会出现内存泄漏的问题,可是在 ThreadLocal 生命周期里面,都有对 key 值为 null 时进行回收的处理操做
因此,使用弱引用的话,能够在 ThreadLocal 生命周期中尽量保证不出现内存泄漏的问题
啥?在 ThreadLcoal 生命周期里面,都有对 key 值为 null 时进行回收的处理操做?有证据么?
那必须得有证据,毕竟阿粉但是个负责任的博主,不过阿粉考虑到这篇文章内容已是比较多的了,因此下篇文章阿粉再带你进行源码分析好很差
乖~
< END >