![DeathNotificationObject DeathNotificationObject]()
我正在尝试实现一种机制,该机制可在保存高速缓存文件的对象死亡时删除高速缓存文件,并决定使用PhantomReference来通知对象的垃圾回收。问题是我一直在经历ReferenceQueue的怪异行为。当我在代码中更改某些内容时,它突然不再获取对象。因此,我尝试制作此示例进行测试,并遇到了相同的问题:public class DeathNotificationObject { private static ReferenceQueue<DeathNotificationObject> refQueue = new ReferenceQueue<DeathNotificationObject>(); static { Thread deathThread = new Thread("Death notification") { @Override public void run() { try { while (true) { refQueue.remove(); System.out.println("I'm dying!"); } } catch (Throwable t) { t.printStackTrace(); } } }; deathThread.setDaemon(true); deathThread.start(); } public DeathNotificationObject() { System.out.println("I'm born."); new PhantomReference<DeathNotificationObject>(this, refQueue); } public static void main(String[] args) { for (int i = 0 ; i < 10 ; i++) { new DeathNotificationObject(); } try { System.gc(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } }}输出为:I'm born.I'm born.I'm born.I'm born.I'm born.I'm born.I'm born.I'm born.I'm born.I'm born.不用说,更改sleep时间,多次调用gc等无效。 更新如所建议的,我调用了我的引用的Reference.enqueue(),从而解决了该问题。奇怪的是,尽管它从未调用enqueue,但我有一些可以完美运行的代码(只是对其进行了测试)。将Reference放入Map是否可能以某种方式神奇地使引用排队?public class ElementCachedImage { private static Map<PhantomReference<ElementCachedImage>, File> refMap = new HashMap<PhantomReference<ElementCachedImage>, File>(); private static ReferenceQueue<ElementCachedImage> refQue = new ReferenceQueue<ElementCachedImage>(); static { Thread cleanUpThread = new Thread("Image Temporary Files cleanup") { @Override public void run() { try { while (true) { Reference<? extends ElementCachedImage> phanRef = refQue.remove(); File f = refMap.remove(phanRef); Calendar c = Calendar.getInstance(); c.setTimeInMillis(f.lastModified()); _log.debug("Deleting unused file: " + f + " created at " + c.getTime()); f.delete(); } } catch (Throwable t) { _log.error(t); } } }; cleanUpThread.setDaemon(true); cleanUpThread.start(); } ImageWrapper img = null; private static Logger _log = Logger.getLogger(ElementCachedImage.class); public boolean copyToFile(File dest) { try { FileUtils.copyFile(img.getFile(), dest); } catch (IOException e) { _log.error(e); return false; } return true; } public ElementCachedImage(BufferedImage bi) { if (bi == null) throw new NullPointerException(); img = new ImageWrapper(bi); PhantomReference<ElementCachedImage> pref = new PhantomReference<ElementCachedImage>(this, refQue); refMap.put(pref, img.getFile()); new Thread("Save image to file") { @Override public void run() { synchronized(ElementCachedImage.this) { if (img != null) { img.saveToFile(); img.getFile().deleteOnExit(); } } } }.start(); }}一些过滤后的输出:2013-08-05 22:35:01,932调试将图像保存到文件:\AppData\Local\Temp\tmp7..0.PNG2013-08-05 22:35:03,379调试删除未使用的文件:\AppData\Local\Temp\tmp7..0.PNG在IDT 2013年8月5日22:35:02创建 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 答案是,在您的示例中PhantomReference本身是不可访问的,因此在之前对垃圾回收对象进行了垃圾回收,所引用的对象本身是垃圾回收的。因此,在对对象进行GC时,不再有Reference了,并且GC不知道它应该在某些地方排队。当然,这是一些正面交锋:-)这也解释了(不希望深入研究新代码)为什么将引用放入一些可访问的集合中可以使示例工作。仅供引用(用于双关语),这是您的第一个示例的修改版本,该示例有效(在我的机器上:-),我刚刚添加了一个包含所有引用的集合。import java.lang.ref.PhantomReference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.util.HashSet;import java.util.Set;public class DeathNotificationObject { private static ReferenceQueue<DeathNotificationObject> refQueue = new ReferenceQueue<DeathNotificationObject>(); private static Set<Reference<DeathNotificationObject>> refs = new HashSet<>(); static { Thread deathThread = new Thread("Death notification") { @Override public void run() { try { while (true) { Reference<? extends DeathNotificationObject> ref = refQueue.remove(); refs.remove(ref); System.out.println("I'm dying!"); } } catch (Throwable t) { t.printStackTrace(); } } }; deathThread.setDaemon(true); deathThread.start(); } public DeathNotificationObject() { System.out.println("I'm born."); PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue); refs.add(ref); } public static void main(String[] args) { for (int i = 0 ; i < 10 ; i++) { new DeathNotificationObject(); } try { System.gc(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } }} 更新在您的示例中可以手动调用enqueue,但不能以实际代码调用。它给出了明显的错误结果。让我通过在构造函数中调用enqueue并使用另一个main进行演示:public DeathNotificationObject() { System.out.println("I'm born."); PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue); ref.enqueue();}public static void main(String[] args) throws InterruptedException { for (int i = 0 ; i < 5 ; i++) { DeathNotificationObject item = new DeathNotificationObject(); System.out.println("working with item "+item); Thread.sleep(1000); System.out.println("stopped working with item "+item); // simulate release item item = null; } try { System.gc(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }}输出将是这样的:I'm born.I'm dying!working with item DeathNotificationObject@6908b095stopped working with item DeathNotificationObject@6908b095这意味着您可以对引用队列执行任何操作,而该条目仍处于 Activity 状态。 (adsbygoogle = window.adsbygoogle || []).push({}); 10-06 03:15