ScheduledExecutorService生命周期?

Xia*_* Xu 4 java multithreading daemon executor

我有一个对象需要定期做一些工作,而对象本身是活着的,所以我设计了类似下面的东西.基本上是一个Main类,它包含对ScheduledExecutorService实例的引用.在此示例中,所有定期工作都是将字符串打印到std.

我希望代码的行为如下:

  1. 调用test2,它创建一个Main对象o1(在其中包含ScheduledExecutorService).
  2. test2寄存器在o1上每秒打印一行.
  3. test2返回,o1变成垃圾.
  4. 系统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();
    }       
}
Run Code Online (Sandbox Code Playgroud)

}

Jim*_*son 7

两个问题:

  1. 默认线程工厂创建非守护程序线程.主线程可以结束,但只要存在活动的非守护程序线程,JVM就不会终止.我相信你需要编写一个创建守护程序线程的自定义线程工厂.
  2. 不要依赖于被调用的终结器 - 不能保证在任何特定时间或任何时候都会调用终结器.此外,System.gc()调用被定义为对JVM 的建议,而不是命令.API文档中的措辞是

调用gc方法表明Java虚拟机花费了很多精力来回收未使用的对象...