学习笔记@Effective Java
文章内容来源于Joshua Bloch - Effective Java (3rd) - 2018.chm一书
第二章
创建和注销对象
Item 8避免Finalizer和Cleaner
// An autocloseable class using a cleaner as a safety net
public class Room implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
// Resource that requires cleaning. Must not refer to Room!
private static class State implements Runnable {
int numJunkPiles; // Number of junk piles in this room
State(int numJunkPiles) {
this.numJunkPiles = numJunkPiles;
}
// Invoked by close method or cleaner
@Override public void run() {
System.out.println("Cleaning room");
numJunkPiles = 0;
}
}
// The state of this room, shared with our cleanable
private final State state;
// Our cleanable. Cleans the room when it’s eligible for gc
private final Cleaner.Cleanable cleanable;
public Room(int numJunkPiles) {
state = new State(numJunkPiles);
cleanable = cleaner.register(this, state);
}
@Override public void close() {
cleanable.clean();
}
}
正如我们前面所说的,房间的Cleaner只是用作安全网。如果客户机在try-with-resource块中包围了所有文件室实例,那么就不需要自动清理。这个行为良好的客户演示了以下行为:
public class Adult {
public static void main(String[] args) {
try (Room myRoom = new Room(7)) {
System.out.println("Goodbye");
}
}
}
正如你所料,运行Adult程序打印Goodbye,然后是打扫房间。但是这个行为不端的程序怎么办,它从不打扫房间?
public class Teenager {
public static void main(String[] args) {
new Room(99);
System.out.println("Peace out");
}
}
你可能期望它打印出Peace out,然后是Cleaning room,但在我的机器上,它从不打印Cleaning room;它只是退出。这就是我们前面提到的不可预测性。规范说,“清洁器在清洁过程中的行为系统出口是特定于实现的。对于是否调用清理操作没有任何保证。”虽然规范没有说明,但对于正常的程序退出也是如此。在我的机器上,添加行垃圾回收()到青少年的主要方法足以使其在退出之前打印到Cleaning room,但不能保证您会在您的机器上看到相同的行为。
总之,不要使用Cleaner,或者在Java9之前的版本中使用终结器,除非作为安全网或终止非关键的本机资源。即便如此,也要注意不确定性和性能后果。