Использование ReferenceQueue и WeakReference

Я хочу правильно закрыть объект 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();
  }

Спасибо заранее. Любая помощь будет оценена.

Ответ 1

Во-первых, если речь идет только о закрытии, используйте 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()