[英]Usage of java.lang.ref.Cleaner as alternative to Object.finalize
我需要清理 JNI 調用分配的資源。 通過覆蓋Object.finalize()
方法很容易做到這一點。 由於從 Java 9 開始不推薦使用此方法,因此我嘗試使用新的java.lang.ref.Cleaner
類來實現相同的目的。
下面是在實例被垃圾回收之前調用ToBeCleaned.cleanUp
方法的代碼:
import java.lang.ref.Cleaner;
import java.lang.ref.WeakReference;
public class ToBeCleaned {
private static Cleaner cleaner = Cleaner.create();
public ToBeCleaned() {
cleaner.register(this, new CleanRunnable(this));
}
void cleanUp () {
// do cleanup
}
static class CleanRunnable implements Runnable {
// It has to be weak reference, otherwise ToBeCleaned instance
// would never be eligible for GC
private WeakReference<ToBeCleaned> toBeCleanedWeakReference;
CleanRunnable(ToBeCleaned toBeCleaned) {
this.toBeCleanedWeakReference = new WeakReference<>(toBeCleaned);
}
@Override
public void run() {
toBeCleanedWeakReference.get().cleanUp();
}
}
}
我的問題:這是正確的方法嗎?
你的方法有缺陷。 “清理操作”不得依賴於對向Cleaner
注冊的實例的訪問權限。
簡而言之,在您的代碼中對toBeCleanedWeakReference.get()
的調用將返回null
因為ToBeCleaned
實例至少從我們的角度來看,到ToBeCleaned
已經被垃圾收集了。
正確的方法是以某種方式引用需要清理的資源,而無需“通過” ToBeCleaned
實例。 通常這意味着:
使清理操作和資源成為同一個對象(與使用Cleaner
注冊的對象不同)。 Cleaner
的文檔展示了這種方法的一個例子。
在實例化它時,將對資源的引用(而不是向Cleaner
注冊的對象)傳遞給清理操作。 下面是一個例子:
public class ToBeCleaned implements AutoCloseable { // documentation suggests you should preferably have one // Cleaner instance per library private static final Cleaner CLEANER = ...; private final Cleaner.Cleanable cleanable; private final SomeResource resource; public ToBeCleaned() { resource = ...; cleanable = CLEANER.register(this, new CleaningAction(resource)); } @Override public void close() { cleanable.clean(); } private static class CleaningAction implements Runnable { private final SomeResource resource; CleaningAction(SomeResource resource) { this.resource = resource; } @Override public void run() { // clean up 'resource' } } }
這兩個示例都實現了AutoCloseable
。 這使您的 API 用戶能夠按需釋放資源,而不是等待垃圾收集器啟動(這使得Cleaner
更像是“備份”)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.