ThreadLocal 详解
ThreadLocal
引用类型
强引用
我们普通的一个对象关系就是强引用。
只有当引用的对象被标记为垃圾的时候才回收。
Object o = new Object();
GC调优经历
在一次上线的项目中,发现应用频繁出现fullGC和运行一段一段时间后,出现out of memory,后面通过排查定位到,是一个类重写了finalize方法,并且有比较耗时的操作。(c++程序员习惯手动析构)。
原因:垃圾回收器在进行gc的时候会执行finalize方法,如果finalize方法操作时间过长,相对于延长了类的生命周期。
软引用
软引用非常适合作缓存。
/**
* 设置jvm参数-Xmx15M
* 堆内存的最大容量为15M
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);//10M的空间
// byte[] bytes1 = softReference.get(); 如果其他变量指向这块内存,则不会回收,相当于强引用
System.gc();//如果内存充足,不会被回收
TimeUnit.SECONDS.sleep(1);
System.out.println(softReference.get());//不为null
byte[] bytes = new byte[1024 * 1024 * 10];//10M的强引用,如果加上之前10M的软引用,则一共20M超过了堆内存的上线
System.out.println(softReference.get());//如果内存不足,被回收,结果为null
}
弱引用
虚引用
public class PhantomRefenerceDemo {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<SoftReference> queue = new ReferenceQueue<>();
//这里虚引用指向了一个软引用
//软引用在内存不足的时候会被自动gc
//会加入到虚引用队列里
PhantomReference<SoftReference> reference = new PhantomReference<>(new SoftReference<>(new byte[1024 * 1024 * 12]), queue);
reference.get();
List<byte[]> list = new ArrayList<>();
new Thread(() -> {
while (true) {
list.add(new byte[1024 * 1024]);
System.out.println("加入内存了");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
while (true) {
Reference<? extends SoftReference> poll = queue.poll();
if (poll != null) {
System.out.println("--虚引用被回收到队列了--");
}
}
}).start();
TimeUnit.SECONDS.sleep(3);
}
}
图例
总结
强软弱四种引用,要gc的第一个条件是,对于堆内存中的对象,除了引用本身,没有其他变量对其进行引用,因为如果有其他变量对其引用,则相当于升级为强引用。
满足这个条件后,强引用是对象满足虚拟机gc的时机。
软引用是当堆内存不足的时候,会清除软引用的内存区域。
弱引用是只要进行gc则一定会清除。
虚引用和以上的用法不同,可以通过一个队列获取清除的对象,主要是用于清除直接内存。
ThreadLocal
set方法
获取到当前线程的map,将ThreadLocal对象作为key,将set的值作为vaule,存入线程的map成员变量里
threadLocal的应用
1、spring中@transaction
2、mybatis的分页
3、自己实现线程安全的一些类成员变量