如何使用PhantomReference作为finalize()替换 [英] How to use PhantomReference as finalize() Replacement

查看:368
本文介绍了如何使用PhantomReference作为finalize()替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Javadoc 8用于 PhantomReference
州:


幻影参考最常用于安排验前清理操作一个比Java终结机制更灵活的方式。

所以我尝试创建一个调用 close()有资格进行垃圾回收的测试对象的方法。 run()尝试获取所有测试对象验前

实际上检索到的测试对象都是 null 。预期的行为是,检索测试对象并调用 close 方法。



无论您创建多少个测试对象,都没有一个测试对象可以被捕获验前(您必须增加超时和多次调用GC)。



我做错了什么?这是一个Java Bug?



Runnable测试代码:



我尝试创建一个完整的和可验证的例子,但它仍然很长。我在Windows 7 64位上使用 java version1.8.0_121 32位。

  public class TestPhantomReference {

public static void main(String [] args)throws InterruptedException {
//创建AutoClose线程并启动它
AutoCloseThread线程=新的AutoCloseThread();
thread.start();

//将10个测试对象添加到AutoClose线程
//测试对象直接符合GC
(int i = 0; i <2; i ++){
thread.addObject(new Test());
}

//睡眠1秒,运行GC,sleep 1秒钟,中断AutoCLose线程
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){
//为带参考队列的测试对象创建PhantomReference,将参考添加到堆栈
mPhantomStack.push(新PhantomReference< Test>(pTest ,mReferenceQueue));
}

@Override
public void run(){
try {
while(true){
//从ReferenceQueue获取PhantomReference并获取
中的测试对象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);

$ b} catch(InterruptedException e){
System.out.println(Thread Interrupted);
}
}
}
}



预计输出:

  System.gc()
测试Obj调用close()
close()

$ b $ / code>



实际输出:

  System.gc()
测试对象为空
测试对象为空
线程中断


解决方案

get ()方法上的幻影引用总是返回null。



目前幻影引用排入的引用对象已被GC收集。您需要将清理所需的数据存储在单独的对象中(例如,您可以继承 PhantomReference )。

这里你可以找到示例代码和更详细的描述关于使用 PhantomReference s。



与终结器不同,幻影引用无法重新生成无法访问的对象。这是它的主要优势,虽然成本是比较复杂的支持代码。

Javadoc 8 for PhantomReference states:

Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.

So I tried creating a thread that is calling the close() method of a Test Object that is eligible for garbage collection. The run() tries to get all Test Objects pre-mortem.

Actually the retrieved Test Objects are all null. The expected behavior is, that the Test Objects are retrieved and the closemethod is called.

No matter how many Test Objects you create there is not a single Test Object that could be caught pre-mortem (You have to increase the timeouts and call GC multiple times).

What am I doing wrong? Is this a Java Bug?

Runnable Test Code:

I tried to create a Minimal, Complete, and Verifiable example, but it's still quite long. I use java version "1.8.0_121" 32-bit on Windows 7 64-bit.

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");
            }
        }
    }
}

Expected Output:

System.gc()
Test Obj call close()
close()
Test Obj call close()
close()
Thread Interrupted

Actual Output:

System.gc()
Test Obj is null
Test Obj is null
Thread Interrupted

解决方案

get() method on phantom references always return null.

At the moment phantom reference is enqueued object it was referencing is already collected by GC. You need to store data required to clean up in separate object (e.g. you can subclass PhantomReference).

Here you can find example code and more elaborate description about using PhantomReferences.

Unlike finalizer, phantom reference cannot resurrect unreachable object. This is its main advantage, though cost is more complicated supporting code.

这篇关于如何使用PhantomReference作为finalize()替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆