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

Я хочу правильно закрыть объект Closeable, когда на него больше не ссылаются другие потоки.

Я написал небольшой тест, но после того, как объект поставлен в очередь, метод 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();
  }

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

2 ответа

Решение

Во-первых, если речь идет только о закрытии, используйте 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 и кстати, если речь идет о файлах, сокетах и ​​т. д., они закрыты для вас (они уже реализуют finalize()

Здесь я хочу упомянуть пару моментов [1] Метод get() не предназначен для использования для задачи завершения . Цель метода get() - получить доступ к объекту-референту, потому что мы используем объект WeakReference для ссылки на объект, на который нет прямой ссылки (т.е. не очень доступный). Референтный объект может быть удален сборщиком мусора в любое время. Ожидается, что метод get() будет возвращать референтный объект до тех пор, пока он не перестанет собираться сборщиком мусора, и возвращает значение null, когда он будет собран сборщиком мусора. Это имеет смысл, потому что объект-референт недоступен после сборки мусора. Метод get() не предназначен для выполнения задачи завершения, такой как закрытие объекта Closable. [2] Подход к завершению задачи непростой.Подход к выполнению задачи финализации состоит в том, чтобы получить объект WeakReference после того, как он поставлен в очередь в сборку мусора после публикации ReferenceQueue. и вызовите его метод clear(). Референтный объект не может выполнять финализацию. Потому что в этот момент считается, что объект-референт был собран сборщиком мусора. Подход состоит в том, чтобы иметь настраиваемую реализацию объекта Reference, который расширит WeakReference. Вы можете переопределить метод clear(), чтобы разместить любую логику очистки. Тем не менее, у вас не может быть ссылки на объект-источник в реализации, поскольку он блокирует сборщик мусора для объекта-источника. Если вам нужно очистить некоторые состояния, например, у референтного объекта есть какой-то близкий объект или соединение и т. Д.,они должны быть сохранены как переменная экземпляра в реализации, а в методе clear они могут быть завершены. При вызове метода clear() будет выполняться логика завершения. Таким образом, объект Reference облегчит завершение.[3] Тем не менее, вышеупомянутый подход здесь бесполезен.поскольку даже настраиваемая реализация объекта WeakReference не может сохранять ссылку на сам объект-референт, поскольку она блокирует объект-референт для сбора мусора. Вы столкнулись с такой трудностью, потому что использование WeakReference для Closeble и ожидание его закрытия в качестве посмертного действия - неправильный вариант использования. Потому что закрытие Closeble не квалифицируется как вскрытие. Посмертная деятельность - это то, что делается после того, как объект был собран сборщиком мусора, т.е. он вообще не имеет своего состояния. Закрытие объекта Closeble - это предварительная операция, т. Е. Ожидается, что она будет выполнена в блоке finally или в потоке, в котором он был создан. Нет смысла откладывать это после сборки мусора Closeble.ReferenceQueue разработан для использования при вскрытии, а не при обследовании.

Другие вопросы по тегам