ScheduledExecutorService和Shutdown Hook

时间:2015-10-07 00:51:26

标签: java executorservice scheduledexecutorservice

当我使用ScheduledExecutorService(或ExecutorService)并提交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);
  }
}

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

2 个答案:

答案 0 :(得分:3)

来自Runtime#addShutdownHook(Thread)的javadoc:

  

Java虚拟机关闭以响应两种   事件:

     
      
  • 当最后一个非守护程序线程退出或调用退出(等效,System.exit)方法时,程序正常退出
  •   
  • 虚拟机终止以响应用户中断,例如键入^ C或系统范围的事件,例如用户注销或   系统关闭。 *
  •   

正如您自己所说,Executor返回的newSingleThreadScheduledExecutor中的线程不是守护程序线程。因此,必须先退出,然后才能调用shutdown hook。

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

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

答案 1 :(得分:1)

如果您在任务运行后绝对需要关闭执行程序,则可以实现以下内容:

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);
}