使用ReferenceQueue和WeakReference

时间:2012-06-04 07:52:48

标签: java

我希望在不再被其他线程引用时正确关闭Closeable对象。

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

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

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

2 个答案:

答案 0 :(得分:7)

首先,如果仅关闭,请使用PhantomReference。 接下来,poll()从引用队列中不能保证您将获得引用。你永远不会得到实际的对象(指称对象)。

如果您想确保Closeable已关闭,则必须自己跟踪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和BTW中关闭文件,如果是关于文件,套接字等,它们将为您关闭(它们已经实现finalize()

答案 1 :(得分:0)

这里我想提几点

  1. get() 方法不适用于完成任务 get() 方法的目的是访问所指对象,因为我们使用 WeakReference 对象来引用没有直接引用的对象(即不是强可达的)。 引用对象可以随时被垃圾回收。 get() 方法应该返回所指对象,直到它没有被垃圾回收,当它被垃圾回收时返回 null。 这是有道理的,因为所指对象在垃圾回收后不可用。 get() 方法不适用于执行关闭 Closable 对象等终结任务。

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

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