ThreadLocal

ThreadLocal和Thread的关系

首先明白他们之间的关系,之后才能理解ThreadLocal以及它存在的问题。
ThreadLocal类有了一个静态类ThreadLocalMapThread类有一个ThreadLocalMap类的引用。

public class ThreadLocal<T> {
	...
	static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        ...
     }
     ...
 }
public class Thread implements Runnable {
	...
	ThreadLocal.ThreadLocalMap threadLocals = null;
	...
}

threadlocal和thread示例图

我们知道ThreadLocal通过线程隔离的方式来保证共享资源的线程安全。其实就是每个线程中都存储一份共享资源的副本,所以你调用get()或者set()的时候其实是调用ThreadLocalMap的get()set()方法,而这个Map是属于当前的线程的。

get()方法
具体来说,当一个某个线程调用ThreadLocal实例的get()方法时候,简化后的过程是:

  1. 获取当前的Thread
  2. 拿到当前Thread的ThreadLocalMap
  3. 遍历Entry拿到key值为ThreadLocal实例的Entry
  4. 把value返回

set()方法

和get方法差不多的流程:

  1. 获取当前Thread
  2. 拿到Thread的ThreadLocalMap
  3. 调用map的set方法

为什么ThreadLocalMap是弱引用

首先要了解java中的四种引用类型

  • 强引用:只要强引用存在,对象不会被回收
  • 软引用:JVM内存不够的时候才会被回收
  • 弱引用:只能存活到下次GC之前
  • 虚引用:不影响GC回收,只是在对象被回收的时候收到一个通知

假设有如下代码:

ThreadLocal<String> threadlocal = new ThreadLocal<>();
threadlocal.set("xxx");

假设key是强引用,该线程在栈帧创建threadlocal引用,并且是强引用。当线程执行结束,引用关系就没了,但是如果key也是强引用,那么Entry中key还有指向threadlocal实例的引用,导致该对象无法被回收,造成内存泄漏。
为什么是弱引用所以,key要设计成弱引用,就是为了避免内存泄漏问题的。

内存泄漏:不被使用的对象或者变量的内存没有被回收

有弱引用为什么还会出现内存泄漏

正常情况下是没有什么问题的,但是一般项目中都要使用线程池,用了线程池之后,线程执行结束之后可能不会被销毁,那么即使key是弱引用value也不会被回收,同样会造成内存泄漏。
引用链如下:Thread->ThreadLocalMap->Entry->value
所以,要手动调用remove()方法防止内存泄漏。

总结

  • ThreadLocal是通过线程副本隔离的方式来保证线程安全的
  • ThreadLocalMap的key是弱引用主要是为了避免内存泄漏
  • 在使用线程池的应用场景下有弱引用也会出现内存泄漏,主要原因是线程可能不会被销毁,从而导致引用一直存在,需要手动去remove防止内存泄漏
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值