オブジェクト自体が生きている間に定期的に作業を行う必要があるオブジェクトがあるので、次のように設計しました。基本的に、ScheduledExecutorServiceインスタンスへの参照を含むMainクラス。この例では、すべての定期的な作業は、文字列をstdに出力することです。
コードは次のように動作することを期待しています。
- test2が呼び出され、メインオブジェクトo1(その中にScheduledExecutorService)が作成されます。
- test2レジスタを使用して、o1に毎秒1行を出力します。
- test2が戻り、o1がガベージになります。
- システムgcはgco1を起動します。これには、ローカルスケジューラをシャットダウンする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();
}
}
}