博客
关于我
ReferenceQueue的使用
阅读量:797 次
发布时间:2023-02-27

本文共 2881 字,大约阅读时间需要 9 分钟。

Java引用机制与ReferenceQueue的作用

在Java的内存管理体系中,引用类型是管理对象生命周期的核心机制。Java提供了多种引用类型,包括强引用、软引用、虚引用和弱引用。强引用是最常见的引用类型,其特点是不会被垃圾回收器回收,只有在其强引用被释放或被显式地进行回收时,对象才会被GC。然而,强引用存在一个潜在的问题:当一个对象被多个强引用所持有时,内存泄漏问题可能会导致应用程序无法正常运行。

ReferenceQueue的作用

ReferenceQueue(引用队列)是解决强引用管理问题的关键工具。当一个对象没有被任何强引用所持有时,垃圾回收器会将其回收。为了确保在这种情况下能够通知相关线程进行必要的处理,ReferenceQueue提供了一个机制,可以将被回收的对象信息存储起来。具体来说,当一个对象被回收后,其相应的弱引用对象会被放入队列中。我们可以从队列中获取回收的对象信息,并执行反向操作,例如清理相关资源或进行数据恢复。

使用队列监控对象回收

一个典型的例子是监控对象的回收情况。我们可以通过编写一个简单的程序,往一个哈希表中添加大量对象,并使用引用队列跟踪这些对象的回收状态。以下是一个示例:

Object value = new Object();
Map
map = new HashMap<>();
for (int i = 0; i < 10000; i++) {
byte[] bytes = new byte[1 << 20]; // 1MB数组
WeakReference
weakReference = new WeakReference<>(bytes, referenceQueue);
map.put(weakReference, value);
}
// 定义队列处理线程
Thread thread = new Thread(() -> {
try {
while ((k = referenceQueue.remove()) != null) {
System.out.println("回收了:" + k.getReferent());
cnt++;
}
} catch (InterruptedException e) {
// 处理中断异常
e.printStackTrace();
}
});
thread.setDaemon(true);
thread.start();

运行此程序可以观察到,尽管哈希表中存储了10000个对象,但由于我们使用了弱引用,实际回收的对象数量会少于10000。这个例子展示了如何使用引用队列来监控对象的回收情况,并在必要时执行反向操作。

WeakHashMap的实现

在实际应用中,WeakHashMap是一个非常有用的工具类,其内部机制利用了ReferenceQueue来管理键的生命周期。WeakHashMap允许键被弱引用持有,当键被回收后,相应的值会从哈希表中自动移除。为了实现这一点,WeakHashMap内部维护了一个队列,用于存储被回收的键。当执行get、put、contains等方法时,WeakHashMap会清空队列中的旧键,确保哈希表中只存储当前有效的键。

反向操作

在实际应用中,除了监控对象的回收情况外,我们还需要对被回收的对象进行反向操作。例如,在数据库或文件操作中,需要确保在连接被回收后,相关资源被正确关闭。为此,我们可以定义一个自定义的弱引用子类,继承WeakReference,并在回收时执行必要的操作。

class WeakR extends WeakReference {
private Object key;
public WeakR(Object key, ReferenceQueue queue) {
super(queue);
this.key = key;
}
public Object get() {
return key;
}
}

在哈希表中,我们使用WeakR作为值来存储键和自定义处理逻辑:

Map
hashMap = new HashMap<>();
for (int i = 0; i < 10000; i++) {
byte[] bytesKey = new byte[1 << 20];
byte[] bytesValue = new byte[1 << 20];
WeakR weakR = new WeakR(bytesKey, referenceQueue);
hashMap.put(bytesKey, weakR);
}

当弱引用被回收后,队列中将存储WeakR对象。我们可以从队列中获取WeakR对象,并执行反向操作:

int cnt = 0;
while ((k = referenceQueue.remove()) != null) {
System.out.println("回收了:" + k.getReferent());
hashMap.remove(k.getReferent());
cnt++;
}

Google Guava的实现

在Google Guava库中,提供了FinalizableReference类,它结合了弱引用和队列机制,提供了更简洁的使用方式。FinalizableReference在对象被回收后,会自动调用回调方法,无需手动从队列中获取对象信息。

FinalizableReference ref = new FinalizableReference<>(bytesKey, referenceQueue) {
@Override
protected void finalize() {
// 在对象被回收时进行处理
System.out.println("处理了:" + getReferent());
}
};
ref referent = bytesKey;
hashMap.put(referent, ref);

FinalizableReference的优势在于其自定义性和简洁性,适合在需要自定义回调的场景中使用。

总结

通过以上内容可以看出,ReferenceQueue是一种强大的工具,能够帮助开发者有效管理对象的生命周期。在实际应用中,合理使用引用队列可以显著提高内存管理效率,减少内存泄漏的风险。无论是监控对象回收,还是执行反向操作,ReferenceQueue都提供了强有力的支持。

转载地址:http://fevfk.baihongyu.com/

你可能感兴趣的文章
oracle dblink结合同义词的用法 PLS-00352:无法访问另一数据库
查看>>
Oracle dbms_job.submit参数错误导致问题(ora-12011 无法执行1作业)
查看>>
oracle dg switchover,DG Switchover fails
查看>>
Oracle EBS环境下查找数据源(OAF篇)
查看>>
Oracle GoldenGate Director安装和配置(无图)
查看>>
oracle script
查看>>
Oracle SOA Suit Adapter
查看>>
Oracle Spatial空间数据库建立
查看>>
UML— 活动图
查看>>
Oracle Statspack分析报告详解(一)
查看>>
oracle 使用leading, use_nl, rownum调优
查看>>
Oracle 写存储过程的一个模板还有一些基本的知识点
查看>>
Oracle 创建 DBLink 的方法
查看>>
oracle 创建字段自增长——两种实现方式汇总
查看>>
Oracle 升级10.2.0.5.4 OPatch 报错Patch 12419392 Optional component(s) missing 解决方法
查看>>
oracle 可传输的表空间:rman
查看>>
Oracle 启动监听命令
查看>>
oracle 学习
查看>>
ORACLE 客户端工具连接oracle 12504
查看>>
oracle 行转列
查看>>