ScheduledExecutorService 和 Shutdown 挂钩

ScheduledExecutorService and Shutdown Hook

当我使用 ScheduledExecutorService(或 E​​xecutorService)并提交 Runnable 时,我的关闭挂钩从未被调用。例如,此程序挂起:

public class App {
  static ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();

  static {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        exec.shutdownNow();
      }
    });
  }

  public static void main(String[] args) {
    exec.schedule(new Runnable() {
      @Override
      public void run() {
      }
    }, 10, TimeUnit.SECONDS);
  }
}

由于执行者的线程不是守护进程,我希望调用关闭挂钩,但事实并非如此。知道为什么吗?

来自 Runtime#addShutdownHook(Thread) 的 javadoc:

The Java virtual machine shuts down in response to two kinds of events:

  • The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
  • The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.*

正如您自己所说,newSingleThreadScheduledExecutor 返回的 Executor 中的线程不是守护线程。所以他们必须在你的关闭钩子被调用之前退出。

你在倒退。您需要从程序执行的其他部分关闭 Executor,而不是关闭挂钩。 Executor 终止后,关闭挂钩将 运行。

* 假设您没有尝试向 java 进程发送用户中断。

如果您绝对需要在任务完成后关闭执行程序 运行,您可以执行如下操作:

static {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            Logger.getGlobal().info("destroying");
            exec.shutdownNow();
        }
    });
}

public static void main(String[] args) throws Exception {
    Future f = exec.schedule(new Runnable() {
        @Override
        public void run() {
            Logger.getGlobal().info("thread run");

        }
    }, 10, TimeUnit.SECONDS);
    while (!f.isDone()) {
        Logger.getGlobal().info("waiting for task to finish");
        Thread.sleep(1000);
    }
    Runtime.getRuntime().exit(0);
}