有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

ReferenceQueue的java含义

我试图理解类ReferenceQueue

它是的可选构造函数参数

SoftReference

WeakReference

它也是PhantomReference的强制参数

根据我读到的信息,我可以写一些论文

a)对于PhantomReference方法,get始终返回null

(b) 对于幻影参考:
1.gc检测到可以从内存中删除对象
2.对放入引用队列的对象的引用
当我们从队列调用clear或link-to-reference时,因为无法访问而gc看到 3.finalize方法调用
4.可用内存
对于弱/软引用:
1.gc检测到可以从内存中删除对象
2.finalize方法调用
3.可用内存
4.对放入队列的对象的引用

  1. 什么时候可以将第二个参数传递给XXXReference构造函数
  2. 我能得到什么帮助
  3. 为什么PhantomReference没有ReferenceQueue的构造函数
  4. 有ReferenceQuee的get方法总是返回null的原因是什么

共 (2) 个答案

  1. # 1 楼答案

    1) When can I pass second argument to XXXReference constructor?

    你想什么时候做就什么时候做。当引用被破坏时,只要需要处理引用,就应该这样做

    2) Which help I can get?

    我不明白这个问题

    3) Why PhantomReference has not constructor without ReferenceQueue ?

    PhantomReference的目的是成为一个比常规定稿更灵活的替代方案。但是,为了使其工作,必须将引用排入队列,以使最终完成替换代码工作。(无法处理未排队的PhantomReference。)

    相比之下SoftReferenceWeakReference对象通常在不排队的情况下很有用

    4) What the reason to have ReferenceQueue which get methods returns null always?

    ReferenceQueueAPI没有get()方法,所以我猜您是在谈论PhantomReferenceAPI。存在get()方法的原因是为了与超类兼容。get()被定义为返回null的原因如下:

    "In order to ensure that a reclaimable object remains so, the referent of a phantom reference may not be retrieved: The get method of a phantom reference always returns null."

    (见javadoc。)

    换句话说,这样做是为了使所指对象不可能“复活”

    更新

    事实上,所有Reference类都将在将Reference排队之前清除引用对象。(实际上,GC本身直接执行此操作。)从ReferenceQueue提取引用的应用程序代码不能使用get()方法来标识(现在已删除!)参照物。他们必须以另一种方式去做;e、 g.基于参考对象的标识

    幻影引用的区别在于get()方法总是返回null。(所以javadoc中的解释……不令人信服。)

  2. # 2 楼答案

    也许,以下程序有点帮助:

    public class SimpleGCExample {
        public static void main(String[] args) throws InterruptedException {
            ReferenceQueue<Object> queue=new ReferenceQueue<>();
            SimpleGCExample e = new SimpleGCExample();
            Reference<Object> pRef=new PhantomReference<>(e, queue),
                              wRef=new WeakReference<>(e, queue);
            e = null;
            for(int count=0, collected=0; collected<2; ) {
                Reference ref=queue.remove(100);
                if(ref==null) {
                    System.gc();
                    count++;
                }
                else {
                    collected++;
                    System.out.println((ref==wRef? "weak": "phantom")
                                      +" reference enqueued after "+count+" gc polls");
                }
            }
        }
    
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalizing the object in "+Thread.currentThread());
            Thread.sleep(100);
            System.out.println("done finalizing.");
        }
    }
    

    在我的系统上,它打印

    weak reference enqueued after 1 gc polls
    finalizing the object in Thread[Finalizer,8,system]
    done finalizing.
    phantom reference enqueued after 2 gc polls
    

    finalizing the object in Thread[Finalizer,8,system]
    weak reference enqueued after 1 gc polls
    done finalizing.
    phantom reference enqueued after 2 gc polls
    

    由于多线程,前两条消息的顺序有时会有所不同。有时,幻影引用报告在三次轮询后进入队列,这表明它花费的时间超过了指定的100毫秒

    关键是

    • 软引用和弱引用在开始终结之前或之后被清除并排队
    • 假设对象没有泄漏finalize方法,则幻象引用在终结后进入队列,否则在对象再次变得不可访问后,幻象引用进入队列
    • (非平凡的)finalize()方法的存在导致至少需要一个额外的垃圾收集周期来检测对象是否再次不可访问或幻影可访问

    由于超过99%的对象不需要最终确定,因此强烈建议所有JVM供应商检测finalize()何时未被重写或是“微不足道的”,即空方法或唯一的super.finalize()调用。在这些情况下,应省略最终确定步骤。通过删除上面示例中的finalize()方法,可以轻松地检查JVM中是否发生了这种优化。然后打印出来

    weak reference enqueued after 1 gc polls
    phantom reference enqueued after 1 gc polls
    

    由于这两条消息同时排队并以任意顺序检索,因此这两条消息的顺序可能不同。但它们总是在一个gc循环后排队

    值得注意的是,幻象引用不会自动清除,这意味着在对象的内存真正可以重用之前需要另一个垃圾收集周期,因此上面的示例需要至少三个周期(使用非平凡的finalize()方法)和两个周期(不使用)。Java9将改变这一点,自动清除幻影引用,因此在上面的示例中,需要两个周期完成,一个周期不完成,直到真正可以回收内存。准确地说,在这个简单的例子中,对象的内存永远不会被回收,因为程序会在这之前终止


    上面的代码还演示了参考API的一个预期用例。我们可以使用它来检测在我们完全控制下的代码中对象的可达性何时发生了变化,例如使用main方法中的循环。相反,finalize()可以在任意时间由不同的、未指定的线程调用。该示例还显示,您可以从引用对象中提取信息,而无需使用get()方法

    实际应用程序通常使用引用类的子类向它们添加更多信息。这就是WeakHashMap.Entry的情况,它扩展了WeakReference并记住哈希代码和值。清理可以在正常的映射操作中完成,不需要任何线程同步。这对于finalize()方法是不可能的,除了map实现不能将finalize()方法推送到键类之外

    这意味着“比定稿更灵活”一词

    WeakHashMap演示了get()方法是如何有用的。只要没有收集到密钥,它就会被报告为在映射中,并且可以在迭代所有密钥或条目时检索到

    已覆盖PhantomReference.get()方法,以始终返回null,以防止应用程序可以恢复排队引用的引用对象。这是“虚拟引用未自动清除”规则的直接后果。这条规则本身是有问题的,它的初衷是在黑暗中。虽然规则将在下一个Java版本中更改,但我担心get()将继续返回null以向后兼容