0
点赞
收藏
分享

微信扫一扫

关于 JDK 中引用队列使用的两个 Bug

王远洋 2022-12-22 阅读 120


可能涉及到 JDK的两个 Bug,但也是一个几乎不会遇到的场景,记录一下,只能说一入 Java 深似海,大周末的,图个乐呵。

关于 Java 弱引用和引用队列,我们一般是这么认为的,这里引用网上一篇博客的说明:

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。


但是经过一些代码测试和考证,是发现这个结论不一定成立的。

首先看一下 ​​java.lang.ref.Reference#enqueue​​ 方法:

/**
* Adds this reference object to the queue with which it is registered,
* if any.
*
* <p> This method is invoked only by Java code; when the garbage collector
* enqueues references it does so directly, without invoking this method.
*
* @return <code>true</code> if this reference object was successfully
* enqueued; <code>false</code> if it was already enqueued or if
* it was not registered with a queue when it was created
*/
public boolean enqueue() {
return this.queue.enqueue(this);
}

大意就是说这个方法虽然是用 Java 代码写的,但是垃圾收集器会直接调用。

再看 ​​java.lang.ref.Reference#isEnqueued​​ 方法:

/**
* Tells whether or not this reference object has been enqueued, either by
* the program or by the garbage collector. If this reference object was
* not registered with a queue when it was created, then this method will
* always return <code>false</code>.
*
* @return <code>true</code> if and only if this reference object has
* been enqueued
*/
public boolean isEnqueued() {
return (this.queue == ReferenceQueue.ENQUEUED);
}

也就是说这个方法返回 true,就说明引用对象入队了。

代码测试:

package dongguabai.spring.mu;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

/**
* @author Dongguabai
* @description
* @date 2021-03-06 21:50
*/
public class ReferenceDemo {

public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
m1();
}
}

private static void m1() {
ReferenceQueue referenceQueue = new ReferenceQueue();

Reference<String> weakReference = new WeakReference<>(new String("abcd"),referenceQueue);

System.out.println("before gc。。。");

System.out.println(weakReference.get());
System.out.println(referenceQueue.poll());
System.out.println(weakReference.isEnqueued());

System.gc();
System.out.println("after gc。。。");

System.out.println(weakReference.get());
System.out.println(referenceQueue.poll());
System.out.println(weakReference.isEnqueued());
System.out.println("-------------------");
}
}

代码流程很简单,就是想模拟出弱引用对象被回收后入队的情况,但是输出结果:

before gc。。。
abcd
null
false
after gc。。。
null
null
true
-------------------
before gc。。。
abcd
null
false
after gc。。。
null
java.lang.ref.WeakReference@61bbe9ba
false
-------------------
before gc。。。
abcd
null
false
after gc。。。
null
java.lang.ref.WeakReference@610455d6
false
-------------------
...
...

发现了两个问题:

  • 弱引用对象在 GC 后不一定会入队(经过不严谨的多次测试,是第一次不会入队);
  • 同时 ​​java.lang.ref.Reference#isEnqueued​​​ 方法的注释说反了,应该是没入队会返回 ​​true​​;

当然这两个问题也已经有人反馈了,这里是相关链接:

  • ​​https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8052260​​
  • ​​https://bugs.java.com/bugdatabase/view_bug.do?bug_id=5047199​​

最后做一个总结:

  • 代码还是实践出真知;
  • 如果要使用虚引用和引用队列做一些生产者/消费者的行为,最好严格测试;

关于 JDK 中引用队列使用的两个 Bug_弱引用


举报

相关推荐

0 条评论