弱引用、虚引用、finalize实践,及它们的顺序
来源:互联网 发布:网络吃火锅是什么意思 编辑:程序博客网 时间:2024/06/05 11:28
说到Java的java.lang.ref.Reference
有四个子类,大家是不是马上想到了强软弱虚?
实际不是,这四个子类是SoftReference
、WeakReference
、PhantomReference
和FinalReference
。
四个子类中没有强引用,没什么奇怪的,但是多出来一个FinalReference
就有意思了。
正好在研究虚引用,写个例子,看看弱引用、虚引用、FinalReference都有什么区别。
代码
代码中,存在实现了非空finalize()
方法的Test
类,main
方法中构造了一个Test
类的对象test
,并在test
上添加了弱引用和虚引用,关联引用队列queue
。
接下来在去除test
的强引用后,两次调用System.gc()
,观察输出。
同时,有另外一个监视线程随时检查引用队列queue
,一旦发现引用就会打印出来。
import java.lang.ref.PhantomReference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.WeakReference;public class PhantomReferenceTest { public static void main(String[] args) throws Exception { ReferenceQueue<Test> queue = new ReferenceQueue<>(); Thread moniterThread = new Thread(() -> { // 监视线程,随时检查引用队列,一旦发现引用就会打印出来 for (;;) { Reference<? extends Test> ref = queue.poll(); if (ref != null) { System.out.printf("%s加入引用队列%n", ref.getClass().getSimpleName()); } try { Thread.sleep(0); } catch (InterruptedException e) { break; } } }); moniterThread.start(); Test test = new Test(); WeakReference<Test> weakReference = new WeakReference<Test>(test, queue); PhantomReference<Test> phantomReference = new PhantomReference<Test>(test, queue); // 去除强引用 test = null; System.out.println(">> 第一次gc <<"); System.gc(); // 这里等待一段时间,保证引用进入队列,和finalize()方法执行 Thread.sleep(100); System.out.println("\n>> 第二次gc <<"); System.gc(); assert weakReference != null && phantomReference != null; moniterThread.interrupt(); } public static class Test { @Override protected void finalize() throws Throwable { System.out.println("== finalize() =="); } }}
分析输出
运行时添加了-XX:+PrintGC
参数,输出结果如下:
>> 第一次gc <<[GC (System.gc()) 3335K->848K(125952K), 0.0824715 secs][Full GC (System.gc()) 848K->749K(125952K), 0.0100622 secs]WeakReference加入引用队列== finalize() ==>> 第二次gc <<[GC (System.gc()) 3411K->1013K(125952K), 0.0009536 secs][Full GC (System.gc()) 1013K->937K(125952K), 0.0148106 secs]PhantomReference加入引用队列
从输出结果中我们能得到如下信息:
- 第一次gc,对象的
finalize()
方法被执行,弱引用进入队列。这两个动作不确定顺序。 - 第二次gc,虚引用进入队列。
接下来详细解释一下代码执行过程中航都发生了什么:
- test对象创建。因为test对象具有非空的finalize方法,所以在test对象的初始化过程中有个特殊的步骤,就是把这个对象包装成一个
java.lang.ref.Finalizer
塞到Finalizer
类的静态链表unfinalized
中。 - 给test对象添加弱引用和虚引用,并执行
test = null;
,此时test对象没有强引用,只有弱引用和虚引用,满足了被垃圾回收的条件。 - 触发gc。jvm准备把test对象回收掉之前,会把它存在的弱引用对象添加到关联的引用队列中。但是,又因为test对象具有finalize方法,所以test对象不会被回收,而是把它的Finalizer添加到
Finalizer
类的静态引用队列queue
中。 - 我们代码中有一个线程一直监视着我们的引用队列,Finalizer的代码中也启动过一个
java.lang.ref.Finalizer.FinalizerThread
线程一直监视着Finalizer的引用队列。我们的监视线程发现队列变化,就打印出“WeakReference加入引用队列”;FinalizerThread发现队列变化,就执行test对象的finalize方法,打印出“== finalize() ==”。这两个线程说不定谁先发现自己的队列发生变化,因此上面的输出信息顺序不确定。 - 第二次触发gc,这次test对象直接被回收掉,之后把关联的虚引用加入队列中,被监视线程监视到,打印出“PhantomReference加入引用队列”。
结论
很多时候,我们认为一个对象的finalize()
方法执行过以后,如果对象没有自救,这个对象马上就被垃圾回收了。但是实际不然,有个时间差,要到下次垃圾回收时才会真正回收掉这个对象。
另外,请避免使用finalize()
方法。
那么,弱引用和虚引用的区别?
只要jvm有回收掉一个对象的意愿,不管最终有没有回收掉,都会在回收对象之前将弱引用加入到引用队列。
而只有在jvm真正回收掉对象之后,才会把虚引用加入引用队列。
0 0
- 弱引用、虚引用、finalize实践,及它们的顺序
- Java中弱引用、软引用、虚引用及强引用的区别
- Java中弱引用、软引用、虚引用及强引用的区别
- Java中弱引用、软引用、虚引用及强引用的区别
- Java中弱引用、软引用、虚引用及强引用的区别
- 输入两个整数,将它们按由大到小的顺序输出。要求使用变量的引用
- C++:输入两个整数,将它们按从小到大的顺序输出(使用变量的引用)
- 强引用 软引用 弱引用 虚引用的区别
- 强引用,软引用,弱引用,虚引用的区别
- Java的强引用、软引用、弱引用、虚引用
- 强引用,软引用,弱引用,虚引用的使用
- 强引用,软引用,弱引用,虚引用的对比
- java的强引用,软引用,弱引用,虚引用
- 强引用、弱引用、软引用、虚引用的理解
- java的强引用、软引用、弱引用、虚引用
- 关于finalize机制和引用、引用队列的一些结论
- easyUI的引用顺序
- android中四大引用的区别,强引用、软引用、弱引用和虚引用
- Unity3d android 通信之 unity3d读取android SD卡文件
- 深度学习与人脸识别系列(2)__基于VGGNet的人脸识别系统
- CF#804 B. Minimum number of steps(字符串,思维)
- FL2440——Gadget驱动实现模拟U盘功能
- Java学习笔记---多线程同步的五种方法
- 弱引用、虚引用、finalize实践,及它们的顺序
- centos安装中文输入法
- Hibernate的基本CRUD
- 另一个.lua文件中的全局变量可以被其它.lua文件读取
- java笔记--关于线程同步(7种同步方式)
- 实现定位服务的两种方法
- 深度学习与人脸识别系列(3)__利用caffe训练深度学习模型
- Codeforces Round #411 (Div. 2) 题解
- 30多年的程序员生涯总结