我有一個對象需要定期做一些工作,而對象本身是活着的,所以我設計瞭如下內容。基本上是一個Main類,它包含對ScheduledExecutorService實例的引用。在這個例子中,所有的定期工作是打印一個字符串到std。ScheduledExecutorService生命週期?
我期望的代碼的行爲如下所示:
- test2的被調用,它創建一個主要目標O1(內它ScheduledExecutorService的)。
- test2寄存器在o1上每秒鐘打印一行。
- test2返回,o1變成垃圾。
- 系統gc啓動到gc o1,它有一個關閉它的本地調度程序的終止方法。
但是,如果我運行這個程序,會發生什麼,它會繼續前進。基本上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();
}
}
}
好吧,似乎System.gc()在這種情況下工作,就好像我註釋掉了註冊方法的調用一樣,GC實際上是通過調用System.gc()來正確踢入的。看起來在調度程序中使用的一些靜態上下文包含對匿名Runnable對象的父對象的引用。 我重構了我的代碼以避免此問題。 – 2010-08-03 05:51:16