虚引用是Java中4种引用类型之一,它的作用主要是用于跟踪垃圾回收器回收对象的生命周期。当一个对象仅仅持有虚引用时,它就相当于未被引用。它的唯一作用是在这个对象被垃圾回收器回收时,能够收到一个系统通知,以便进行必要的资源清理操作。换句话说,虚引用提供了一种机制,使得我们可以在对象被垃圾回收器回收时,清理一些资源。
使用虚引用需要借助于java.lang.ref
包中的PhantomReference
类。其构造方法如下:
public PhantomReference(T referent, ReferenceQueue<? super T> queue)
其中,referent
参数是被引用的对象,而queue
则是用于接收回收通知的队列。我们可以通过该队列的remove()
方法来获取被回收的对象。
以下是两个示例说明:
- 在垃圾回收时清理一些外部资源
假设有一个文件管理器类FileManager
,其中的文件对象可以通过getFile()
方法获取。我们希望在文件对象被回收时,同时删除磁盘上对应的文件。可以通过虚引用来实现:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileManager {
private final ReferenceQueue<File> queue = new ReferenceQueue<>();
public class FileManagerReference extends PhantomReference<File> {
private final Path filePath;
public FileManagerReference(File file, Path filePath) {
super(file, queue);
this.filePath = filePath;
}
public void cleanup() {
if (Files.exists(filePath)) {
try {
Files.delete(filePath);
} catch (IOException e) {
// 忽略删除失败的情况
}
}
}
}
public File getFile(String path) {
File file = new File(path);
FileManagerReference reference = new FileManagerReference(file, file.toPath());
// 将虚引用存放到WeakReference列表中,这样referent将被赋值为null
return reference.get();
}
public void processQueue() {
FileManagerReference reference;
while ((reference = (FileManagerReference) queue.poll()) != null) {
reference.cleanup();
}
}
}
在getFile()
方法中,我们创建了一个FileManagerReference
虚引用,并将它添加到列表中。由于引用类型的特性,FileManagerReference
对象会在被垃圾回收时放入queue
队列中。在processQueue()
方法中,我们可以从队列中获取一个FileManagerReference
对象,并调用它的cleanup()
方法来删除磁盘上对应的文件。
- 检测对象的生命周期
假设有一个订单管理器类OrderManager
,其中的订单对象可以通过getOrder()
方法获取。我们希望在订单对象被回收时,能够及时得到通知并记录日志。可以通过虚引用来实现:
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class OrderManager {
private final ReferenceQueue<Order> queue = new ReferenceQueue<>();
public class OrderReference extends PhantomReference<Order> {
private final String orderId;
public OrderReference(Order order, String orderId) {
super(order, queue);
this.orderId = orderId;
}
public void logEvent(String event) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("Event: " + event);
pw.println("Order ID: " + orderId);
pw.println("Timestamp: " + System.currentTimeMillis());
pw.println();
System.out.println(sw.toString());
}
}
public Order getOrder(String orderId) {
Order order = new Order(orderId);
OrderReference reference = new OrderReference(order, orderId);
// 将虚引用存放到WeakReference列表中,这样referent将被赋值为null
return reference.get();
}
public void processQueue() {
OrderReference reference;
while ((reference = (OrderReference) queue.poll()) != null) {
reference.logEvent("Order destroyed");
}
}
}
在getOrder()
方法中,我们创建了一个OrderReference
虚引用,并将它添加到列表中。由于引用类型的特性,OrderReference
对象会在被垃圾回收时放入queue
队列中。在processQueue()
方法中,我们可以从队列中获取一个OrderReference
对象,并调用它的logEvent()
方法来记录日志。
注意,在以上两个示例中,为了使虚引用得到正确的处理,需要定期调用processQueue()
方法来处理队列。可以通过一个单独的线程来进行处理,或者在业务逻辑中定期调用。