我有一个对象需要在对象本身还活着的时候定期做一些工作,所以我设计了类似下面的东西。基本上是一个 Main 类,其中包含对 ScheduledExecutorService 实例的引用。在此示例中,所有定期工作是将字符串打印到 std。
我希望代码的行为如下:
- test2 被调用,它创建了一个 Main 对象 o1(其中有一个 ScheduledExecutorService)。
- test2 寄存器在 o1 上每秒打印一行。
- test2 返回,o1 变成垃圾。
- 系统 gc 启动到 gc o1,它有一个 finalize 方法来关闭它的本地调度程序。
但是,如果我运行这个程序,会发生什么,它将永远持续下去。基本上 gc 永远不会调用 o1 的终结器,因此调度程序永远不会关闭,因此即使主线程结束,程序仍然不会退出。
现在,如果我在 test2() 中注释掉 o1.register,程序的行为就像它应该的那样,例如调用 gc 等。此外,在调试器中,似乎只有在调用 ScheduledExecutorService.schedule 之后才会创建实际线程。
任何解释发生了什么?
public class Main {
public static void main(String[] args) throws Exception {
test2();
System.gc();
System.out.println("Waiting for finalize to be called..");
Thread.sleep(5000);
}
private static void test2() throws Exception {
Main o1 = new Main();
o1.register();
Thread.sleep(5000);
}
private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
private void register() {
_scheduler.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
System.out.println("!doing stuff...");
}
}, 1, 1, TimeUnit.SECONDS);
}
@Override
protected void finalize() throws Throwable {
try {
System.out.print("bye");
_scheduler.shutdown();
} finally {
super.finalize();
}
}
}