Использование 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 разработан для использования при вскрытии, а не при обследовании.