キャッシュされたファイルを保持するオブジェクトが消滅したときに、キャッシュされたファイルを削除するメカニズムを実装しようとしていて、オブジェクトのガベージコレクションで通知を受け取るために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();
}
}
}
出力は次のとおりです。sleep
時間を変更し、言うこと
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.
言うまでもなく、gc
複数回などを呼び出しますうまくいかなかった。
UPDATE
示唆したように、私は問題を解決した、私の参照の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年8月5日22:35:01932 DEBUG保存画像ファイルへ:<> \のAppData \ローカル\ Tempにを\ tmp7..0.PNG
2013-08-05 22:35:03,379 DEBUG未使用ファイルを削除する:<> \ AppData \ Local \ Temp \ tmp7..0.PNG Mon Aug 05 22:35:02 IDT 2013
実際には何もエンキューしません。 –
だから私は 'enqueue()'を呼び出すべきです...それを得ました、ありがとう! – Elist
私の答え、最後の行を参照してください。 –