引用队列 ReferenceQueue

如果有什么错误的地方,希望指出。

前几天有个面试,在面试最后的时候,面试官说问个比较偏僻的知识点,问了关于Java引用的。于是我就把四种引用说了下。然后又问,你知道引用队列嘛?然后我懵逼了,只能说我不知道。

关于Java中的引用,可以看上面的链接,引用主要用于GC中的。

引用队列 ReferenceQueue 是用来配合引用工作的,没有 ReferenceQueue 一样可以运行。创建引用的时候可以指定关联的队列,当GC释放对象内存的时候,会将引用加入到引用队列的队列末尾,这相当于是一种通知机制。当关联的引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。通过这种方式,JVM允许我们在对象被销毁后,做一些我们自己想做的事情。JVM提供了一个ReferenceHandler线程,将引用加入到注册的引用队列中。

关于引用队列,其类位于ref中,如图所示:

1
2
3
4
5
6
7
8
9
10
11
// 引用队列
ReferenceQueue<String> rq = newReferenceQueue<String>();
// 软引用
SoftReference<String> sr = newSoftReference<String>(new String("Soft"),rq);
// 弱引用
WeakReference<String> wr = newWeakReference<String>(new String("Weak"),rq);
// 幽灵引用
PhantomReference<String> pr = newPhantomReference<String>(new String("Phantom"),rq);

// 从引用队列中弹出一个对象引用
Reference<? extends String> ref = rq.poll();

ReferenceQueue 提供了三种方法来移除队列:

  • poll():用于移除并返回该队列中的下一个引用对象,如果队列为空,则返回null
  • remove():用于移除并返回该队列中的下一个引用对象,该方法会在队列返回可用引用对象之前一直阻塞
  • remove (long timeout):用于移除并返回队列中的下一个引用对象。该方法会在队列返回可用引用对象之前一直阻塞,或者在超出指定超时后结束。如果超出指定超时,则返回null。如果指定超时为0,意味着将无限期地等待。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class ReferenceQueueDemo {

private static ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
private static int _1M = 1024 * 1024;

public static void main(String[] args) {

Object object = new Object();
Map<Object, Object> map = new HashMap<>();

Thread thread = new Thread(() -> {
try {
int cnt = 0;
WeakReference<byte[]> k;
while ((k = (WeakReference) referenceQueue.remove()) != null) {
System.out.println((cnt++) + "回收了:" + k);
}
} catch (InterruptedException e) {
//结束循环
}
});
thread.setDaemon(true);
thread.start();

for (int i = 0; i < 10000; i++) {
byte[] bytes = new byte[_1M];
WeakReference<byte[]> weakReference = new WeakReference<>(bytes, referenceQueue);
map.put(weakReference, object);
}
System.out.println("map.size->" + map.size());

}
}

因为map的key是WeakReference,所以在内存不足的时候,weakReference所指向的对象就会被GC,在对象被GC的同时,会把该对象的包装类即weakReference放入到ReferenceQueue里面。但是这个map的大小是10000。

博主 wechat
如果不想经常浏览博客,可以关注公众号,会把博客的文章发送到公众号上
客官,赏一杯coffee嘛~~~~
0%