これがEffectiveJavaの関連項目です:ファイナライザーを避けてください
その項目には、@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