ThreadLocal解析

一、java的引用类型

java的引用类型有四种:强、软、弱、虚

1、强引用

我们平常创建的对象基本上都是强引用,也就是new出来的对象,如Object o = new Object();,这个o直接指向堆内存当中创建的Object对象,如下:
在这里插入图片描述
GC:强引用类型只有在没有引用指向这个对象的时候它才能被回收,否则,即使内存不足,也不会被回收

2、软引用

SoftReference<Object> sr = new SoftReference<>(new Object());

// 获取其中元素
sr.get(); 

如上这句代码就有一个软引用,实际上,我们直接创建的引用一般都是强引用,也就是,我们无法直接指向软引用,如下,我们创建的 sr 对new SoftReference()是强引用,但是new SoftReference()对new Object()是软引用,相当于起到一个中介的作用,也就是 sr 无法直接软引用指向new Object()对象
在这里插入图片描述

GC:软引用在内存不足的时候会被回收,内存足够的话不会被回收

应用:软引用适合在缓存中使用

3、弱引用

WeakReference<Object> wr = new WeakReference<>(new Object());

// 获取其中元素
wr.get();

如上就是一个弱引用的例子,wr 直接强引用指向new WeakReference<>(),new WeakReference<>()则弱引用指向new Object()
在这里插入图片描述
GC:弱引用在垃圾回收的时候直接进行回收

应用:ThreadLocal

4、虚引用

// 引用队列
private static final ReferenceQueue<Object> QUEUE = new ReferenceQueue<>();

PhantomReference<Object> pr = new PhantomReference<>(new Object(),QUEUE);

// 虚引用无法获取其中元素
pr.get();  // 结果为null

如下,内存结构和软、弱引用差不多,只是PhantomReference<>()是虚引用指向new Object(),虚引用甚至无法获取其中元素
在这里插入图片描述
GC:虚引用被回收的时候会被放到一个队列里面,等待jvm单独处理

使用:直接内存的管理;内存一般有操作系统内存以及虚拟机内存,平时正常的请求信息先到达操作系统内存,虚拟机再去从操作系统内存中拷贝一份到虚拟机内存中使用,效率相对较低,所以jvm就使用一个对象来直接指向操作系统内存

二、ThreadLocal

// ThreadLocal 定义
static ThreadLocal<Object> tl = new ThreadLocal<>();

// 添加元素
tl.set(new Object());

// 获取其中元素
tl.get();

ThreadLocal其实只是线程的一个成员变量,也就是,每当我们创建一个线程的时候,都会生成一个ThreadLocalMap的一个容器对象;当我们调用 set() 方法的时候,其实就是将我们自己创建的 tl 作为map的new Object() 作为被存入到当前线程的ThreadLocalMap当中,即threadLocals.put(tl,new Object());

所以,当我们在线程1中调用set()方法的时候,它会把数据存到线程1的ThreadLocalMap中,当我在线程2调用get()方法时,则会从线程2的ThreadLocalMap中去取数据,使用的容器不一样
在这里插入图片描述
如下图,当我们调用ThreadLocal的 set() 方法的时候,会将 tl 作为键,Object作为值存入map中,map中的key对 tl 是弱引用,value对Object则是强引用

在这里插入图片描述

内存泄露

内存泄露问题:如果map中的key对ThreadLocal的引用类型是强引用的话,那如果我们用不到ThreadLocal了,想要回收ThreadLocal,此时即使我们将 tl 置为空(null),但是map中的key对ThreadLocal是强引用,就会导致ThreadLocal不会被回收;

但是如果map中的key对ThreadLocal是弱引用的话,我们只需要将 tl 置为空,GC的时候就会直接回收ThreadLocal;

但此时value依然是强引用,依然不会被回收,所以map每次在我们执行get(),set()方法的时候,都会自动remove键为null的value,但是我们依然需要在不使用ThreadLocal之后,自己手动将value值remove,因为get(),set()有可能长时间不执行

线程池问题:存在一种情况,线程池中线程1在被使用的时候,在ThreadLocalMap中存入了一些数据,之后又被放回线程池,然后又被调用执行,此时可能拿到之前存入的数据,所以,线程池每次线程执行完的时候,都会清理ThreadLocalMap当中的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值