引用队列(ReferenceQueue)浅析

您所在的位置:网站首页 成都大悦城有哪些品牌女装 引用队列(ReferenceQueue)浅析

引用队列(ReferenceQueue)浅析

2023-11-19 07:29| 来源: 网络整理| 查看: 265

什么是引用队列

引用队列,注册的引用型对象(SoftReference、WeakReference、PhantomReference)在垃圾回收器检测到所引用的对象可达性发生改变时,会将这个引用型的对象添加到引用队列中。

可达性改变是什么意思

我们都知道:垃圾回收器会清理掉被弱引用引用着的对象,或者说是具有弱可达性的对象来作为垃圾回收的过程中的一部分。该过程可以这样描述: 如果垃圾回收器发现一个对象具有弱可达性,那么它会 1. 将弱引用(WeakReference)对象的实际引用字段设置为null,因此可以使它不再引用着堆中的对象。 2. 被弱引用引用着的堆中的对象会被声明为是可终结的(finalizable)。 3. 弱引用对象被添加到它的引用队列中。然后在堆中的那个对象会调用finalize()方法,它的内存会被释放掉。

那么引用队列究竟是什么

当创建一个非强引用的引用对象时,可以传一个引用队列对象给Reference构造函数。引用队列是GC通知程序某个对象不可达的信号,装载这个不可达对象引用的容器。 示例代码如下:

public static void main(String[] args) throws InterruptedException { SavePoint savePoint = new SavePoint("Random"); // 创建一个强引用 ReferenceQueue savepointQ = new ReferenceQueue();//引用队列 WeakReference savePointWRefernce = new WeakReference(savePoint, savepointQ); System.out.println("SavePoint 被作为一个弱引用来创建" + savePointWRefernce); Runtime.getRuntime().gc(); System.out.println("在引用队列中存在引用型对象吗 ? " + (savepointQ.poll() != null)); savePoint = null; // 唯一的强引用被删除掉,在堆中的对象现在只具有弱可达性 System.out.println("现在调用GC"); Runtime.getRuntime().gc(); // 对象会在这里被回收掉,finalize方法会被调用 System.out.println("在引用队列中有任何弱引用吗? " + (savepointQ.remove() != null)); System.out.println("弱引用型对象还引用着堆中的对象吗?" + (savePointWRefernce.get() != null)); System.out.println("弱引用型对象被添加到引用队列中了吗?" + (savePointWRefernce.isEnqueued())); }

代码说明如下: 创建一个强引用对象,并将它添加到弱引用中。这个在内存中的对象现在同时被一个强引用和一个弱引用引用着,因此它依然具有强可达性。 首次调用GC并不会清除掉savepoint对象,因为它仍然具有强可达性。因此referenceQ的poll方法会返回null。(poll方法是非阻塞的方法,它会立即返回) savePoint引用型变量被置为null。现在堆中的对象只被弱引用型变量引用着,因此它现在具有弱可达性。 再次调用GC那么就会定位到这个对象上,然后执行它的finalize方法,将它标记为要被释放掉。然后将弱引用型的对象添加进引用队列中。 调用引用队列的remove方法会返回这个对象,并且这个remove方法是一个阻塞方法,它会一直等到在队列中有可用的引用型对象。(poll方法不会像回收过程那样发生在分离的线程中) 运行结果如下:

SavePoint 被作为一个弱引用来创建java.lang.ref.WeakReference@2a139a55 在引用队列中存在引用型对象吗 ? false 现在调用GC 在引用队列中有任何弱引用吗? true 弱引用型对象还引用着堆中的对象吗?false 弱引用型对象被添加到引用队列中了吗?false

一旦某个对象被释放掉,它的引用型对象会被添加到引用队列,因此引用队列就像是java程序中的回调函数。这样就能告诉程序员:一个特定的对象已经从它的引用中被释放掉了,我们的代码不能再次引用到这个对象了。 那么我们能够再次使用用引用队列中的对象吗 我们知道,finalize方法可以被用来重新依附到对象上,使他们具有强可达性。例如将它们添加到静态列表中。那么这个对象在本次循环中不会再被回收掉。让我们尝试着回收这个对象: 实例代码如下:

public static void main(String[] args) throws InterruptedException { SavePoint savePoint = new SavePoint("Random"); // 创建一个强引用 ReferenceQueue savepointQ = new ReferenceQueue();// 引用队列 WeakReference savePointWRefernce = new WeakReference(savePoint, savepointQ); System.out.println("在队列中有任何弱引用吗? " + (savepointQ.poll() != null)); savePoint = null; System.out.println("现在调用GC..."); Runtime.getRuntime().gc(); // 对象在这里会被清除掉 - finalize方法会被调用 Reference


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3