这是来自Effective Java的相关项目:避免终结器
该项目中包含的建议是执行@delnan 在评论中建议的建议:提供显式终止方法。还提供了大量示例:InputStream.close()
、Graphics.dispose()
等。了解奶牛可能已经离开了那个谷仓......
无论如何,这里有一个关于如何使用参考对象来完成的草图。一、二进制数据的接口:
import java.io.IOException;
public interface Blob {
public byte[] read() throws IOException;
public void update(byte[] data) throws IOException;
}
接下来,基于文件的实现:
import java.io.File;
import java.io.IOException;
public class FileBlob implements Blob {
private final File file;
public FileBlob(File file) {
super();
this.file = file;
}
@Override
public byte[] read() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void update(byte[] data) throws IOException {
throw new UnsupportedOperationException();
}
}
然后,创建和跟踪基于文件的 blob 的工厂:
import java.io.File;
import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class FileBlobFactory {
private static final long TIMER_PERIOD_MS = 10000;
private final ReferenceQueue<File> queue;
private final ConcurrentMap<PhantomReference<File>, String> refs;
private final Timer reaperTimer;
public FileBlobFactory() {
super();
this.queue = new ReferenceQueue<File>();
this.refs = new ConcurrentHashMap<PhantomReference<File>, String>();
this.reaperTimer = new Timer("FileBlob reaper timer", true);
this.reaperTimer.scheduleAtFixedRate(new FileBlobReaper(), TIMER_PERIOD_MS, TIMER_PERIOD_MS);
}
public Blob create() throws IOException {
File blobFile = File.createTempFile("blob", null);
//blobFile.deleteOnExit();
String blobFilePath = blobFile.getCanonicalPath();
FileBlob blob = new FileBlob(blobFile);
this.refs.put(new PhantomReference<File>(blobFile, this.queue), blobFilePath);
return blob;
}
public void shutdown() {
this.reaperTimer.cancel();
}
private class FileBlobReaper extends TimerTask {
@Override
public void run() {
System.out.println("FileBlob reaper task begin");
Reference<? extends File> ref = FileBlobFactory.this.queue.poll();
while (ref != null) {
String blobFilePath = FileBlobFactory.this.refs.remove(ref);
File blobFile = new File(blobFilePath);
boolean isDeleted = blobFile.delete();
System.out.println("FileBlob reaper deleted " + blobFile + ": " + isDeleted);
ref = FileBlobFactory.this.queue.poll();
}
System.out.println("FileBlob reaper task end");
}
}
}
最后,一个包含一些人工 GC“压力”的测试来让事情顺利进行:
import java.io.IOException;
public class FileBlobTest {
public static void main(String[] args) {
FileBlobFactory factory = new FileBlobFactory();
for (int i = 0; i < 10; i++) {
try {
factory.create();
} catch (IOException exc) {
exc.printStackTrace();
}
}
while(true) {
try {
Thread.sleep(5000);
System.gc(); System.gc(); System.gc();
} catch (InterruptedException exc) {
exc.printStackTrace();
System.exit(1);
}
}
}
}
这应该产生一些输出,如:
FileBlob reaper task begin
FileBlob reaper deleted C:\WINDOWS\Temp\blob1055430495823649476.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob873625122345395275.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob4123088770942737465.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob1631534546278785404.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob6150533076250997032.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob7075872276085608840.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob5998579368597938203.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob3779536278201681316.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob8720399798060613253.tmp: true
FileBlob reaper deleted C:\WINDOWS\Temp\blob3046359448721598425.tmp: true
FileBlob reaper task end