10

当其他线程不再引用可关闭对象时,我想正确关闭它。

我写了一些小测试,但是在对象入队后,get 方法返回 null,即 poll 方法返回没有引用的正确对象。

  public static void main(String[] args)
  {
   ReferenceQueue<Closeable> reaped = new ReferenceQueue<Closeable>();
   Closeable s = <SOME CLOSEABLE IMPL>;
   WeakReference<Closeable> ws = new WeakReference<Closeable>(s, reaped);
   s = null;

   System.gc();
   Closeable ro = (Closeable)reaped.poll().get();
   ro.close();
  }

提前致谢。任何帮助将不胜感激。

4

2 回答 2

7

首先,如果只是关于关闭,请使用PhantomReference. 接下来,从引用队列中,poll()不保证您会取回引用。并且您将永远无法取回实际对象(所指对象)。

如果您想确保您Closeable的 s 已关闭,您必须自己跟踪它们,让我们在Map<Reference<?>, Closeable>. 然后,当poll()您参考队列时,您最终将获得ref然后您必须使用它Closeable从地图中获取。

   class MyThing {
      Closeable c;
   }

   Map<Reference<MyThing>, Closeable> m = new HashMap();
   ReferenceQueue<MyThing> reaped = new ReferenceQueue<MyThing>();

   MyThing mt = new MyThing();
   mt.c = new MyClosable();

   Reference<MyThing> pref = new PhantomReference<MyThing>(mt, reaped);
   m.put(pref, mt.c);

   mt = null;


   System.gc();
   Reference<MyThing> rf = reaped.poll();
   while (rf != null) {
     m.get(rf).close(); 
     rf = reaped.poll();
   }

注意如果您没有真正的理由这样做,或者如果您不明白自己真正在做什么,请不要这样做。

你可以关闭你的文件finally,顺便说一句,如果它是关于文件、套接字等的,它们是为你关闭的(他们已经实现了finalize()

于 2012-06-04T09:28:01.633 回答
0

这里我想提几点

  1. get()方法不打算用于终结任务get()方法的目的是访问所指对象,因为我们使用WeakReference对象来引用一个没有直接引用的对象(即不是强可达的)。任何时候都可以对所指对象进行垃圾回收。该get()方法预计在没有被垃圾回收之前返回所指对象,并在被垃圾回收时返回 null。这是有道理的,因为引用对象在垃圾回收后不可用。该get()方法不适用于完成诸如关闭Closable对象之类的终结任务。

  2. 完成最终任务的方法并不简单。完成最终任务的方法是在对象进入后期垃圾回收WeakReference队列后检索它。ReferenceQueue并称之为 clear() 方法。您不能让引用对象来完成最终确定。因为此时认为所指对象已被垃圾回收。方法是拥有一个将扩展 WeakReference 的 Reference 对象的自定义实现。您可以覆盖 clear()放置任何清理逻辑的方法。您仍然不能在实现中对引用对象有任何引用,因为它会阻止引用对象被垃圾收集。如果您必须清理一些状态,例如引用对象有一些可关闭的对象或连接等,则需要将它们保存为实现下的实例变量,并且可以在 clear 方法中完成它们。当clear()方法被调用时,终结逻辑将被执行。因此,参考对象将有助于最终确定。

  3. 上述方法在这里仍然没有用,因为即使对象的自定义实现WeakReference也不能保持对引用对象本身的引用,因为它会阻止引用对象被垃圾收集。您正面临这样的困难,因为使用WeakReferenceforCloseble并期望将其作为事后活动关闭不是正确的用例。因为关闭 aCloseble没有资格成为事后活动。事后活动是在一个对象被垃圾收集之后所做的事情,即它根本没有它的状态。关闭一个Closeble对象是一个预先确定的活动,即预期在 finally 块中完成,或者在创建它的线程中完成。在Closeble. ReferenceQueue旨在用于死后活动,而不是用于死前活动。

于 2021-05-08T17:05:42.917 回答