Javadoc 8中的PhantomReference表示:
幻影引用通常用于以比Java终结机制更灵活的方式安排临终清理操作。
因此,我尝试创建一个调用Test对象的close()方法的线程,该对象符合垃圾回收的条件。run()方法试图获取所有的Test对象,在临终之前就被抓住了。
实际上,检索到的所有Test对象都为null。期望的行为是检索到Test对象并调用close()方法。
无论您创建多少个Test对象,都没有一个可以被抓住在临终之前(您必须增加超时时间并多次调用GC)。
我做错了什么?这是Java的错误吗?
可运行的测试代码:
我试图创建一个最小、完整和可验证的示例,但它仍然相当长。我在Windows 7 64位上使用32位的java版本“1.8.0_121”。
幻影引用通常用于以比Java终结机制更灵活的方式安排临终清理操作。
因此,我尝试创建一个调用Test对象的close()方法的线程,该对象符合垃圾回收的条件。run()方法试图获取所有的Test对象,在临终之前就被抓住了。
实际上,检索到的所有Test对象都为null。期望的行为是检索到Test对象并调用close()方法。
无论您创建多少个Test对象,都没有一个可以被抓住在临终之前(您必须增加超时时间并多次调用GC)。
我做错了什么?这是Java的错误吗?
可运行的测试代码:
我试图创建一个最小、完整和可验证的示例,但它仍然相当长。我在Windows 7 64位上使用32位的java版本“1.8.0_121”。
public class TestPhantomReference {
public static void main(String[] args) throws InterruptedException {
// Create AutoClose Thread and start it
AutoCloseThread thread = new AutoCloseThread();
thread.start();
// Add 10 Test Objects to the AutoClose Thread
// Test Objects are directly eligible for GC
for (int i = 0; i < 2; i++) {
thread.addObject(new Test());
}
// Sleep 1 Second, run GC, sleep 1 Second, interrupt AutoCLose Thread
Thread.sleep(1000);
System.out.println("System.gc()");
System.gc();
Thread.sleep(1000);
thread.interrupt();
}
public static class Test {
public void close() {
System.out.println("close()");
}
}
public static class AutoCloseThread extends Thread {
private ReferenceQueue<Test> mReferenceQueue = new ReferenceQueue<>();
private Stack<PhantomReference<Test>> mPhantomStack = new Stack<>();
public void addObject(Test pTest) {
// Create PhantomReference for Test Object with Reference Queue, add Reference to Stack
mPhantomStack.push(new PhantomReference<Test>(pTest, mReferenceQueue));
}
@Override
public void run() {
try {
while (true) {
// Get PhantomReference from ReferenceQueue and get the Test Object inside
Test testObj = mReferenceQueue.remove().get();
if (null != testObj) {
System.out.println("Test Obj call close()");
testObj.close();
} else {
System.out.println("Test Obj is null");
}
}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
}
}
期望输出:
System.gc()
Test Obj call close()
close()
Test Obj call close()
close()
Thread Interrupted
实际输出:
System.gc()
Test Obj is null
Test Obj is null
Thread Interrupted
Test testObj = mReferenceQueue.remove().get();
改为mReferenceQueue.remove().close()
,就可以解决一直返回 null 的问题。queue.remove()
会正确阻塞并始终返回一个对象,因此无需测试是否为null
。 - PaceriermReferenceQueue.remove()
将返回一个Reference<? extends Test>
对象而不是Test
对象,所以我无法调用mReferenceQueue.remove().close()
。也许你可以提供更多细节。 - notes-jj