如何优雅的停止服务(ShutdownHook)

xiaoxiao2021-02-28  17

JDK提供了Runtime.addShutdownHook(Thread hook)方法用来注册一个钩子(线程),在Java程序退出时会调用这个钩子来清理现场。

这个钩子会在以下场景中被调用: 1. 程序正常退出 2. 使用System.exit() 3. 终端使用Ctrl+C触发的中断 4. 系统关闭 5. OutOfMemory宕机 6. 使用Kill pid命令干掉进程(注:在使用kill -9 pid时,是不会被调用的)

下面我们来简单的模拟一个服务,详细说明如何优雅的终止Java进程。

/** * zyc 2017年10月16日 下午3:05:03 */ public class ShutdownHookTest{ private static ExecutorService executorService = Executors.newFixedThreadPool(10); private static final long TIMEOUT = 10 * 1000; public static void main(String[] args) { // 注册钩子函数,在JVM接收到停止指令后会运行该线程 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println("invoke shutdownhook ...."); // 调用该方法把threadpool 的 shutdown 设置为true,不再接受提交任务, // 等待已经提交的任务执行完之后才会退出 executorService.shutdown(); long time = System.currentTimeMillis(); while(true){ int activeCount = ((ThreadPoolExecutor)executorService).getActiveCount(); // 执行中的线程数 int waitCount = ((ThreadPoolExecutor)executorService).getQueue().size(); // 等待的线程数 System.out.println("there are " + waitCount + " threads wait ...."); System.out.println("there are " + activeCount + " threads working ...."); if(executorService.isTerminated()){ // 等待线程池退出 System.out.println("thread pool is shutdown ..."); break; } if(System.currentTimeMillis() - time > TIMEOUT) // 超时 executorService.shutdownNow(); sleep(500); } } })); // 模拟工作环境,不断往线程池提交任务 for(;;){ if(executorService.isShutdown()) break; executorService.submit(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " work ...."); sleep(2 * 1000); // 模拟线程工作 } }); sleep(500); } } private static void sleep(long millis){ try { TimeUnit.MILLISECONDS.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } }

把代码打成Jar包在linux上运行 java –jar ShutdownHookTest.jar,输出如下: 线程池在持续工作,并不断的有任务提交。

执行kill命令终止Java进程 注意:这里用的是kill -15 pid 不是kill -9 pid

Java进程接收到终止指令后,调用钩子方法,直到线程池里的所有任务都执行完毕才退出

本文简单的模拟了关闭服务的场景,通过不断的轮询线程池的状态,直到所有提交的任务执行完毕才终止进程,清理的逻辑在钩子函数的run方法中实现即可,更多的功能请各位自己尝试。

转载请注明原文地址: https://www.6miu.com/read-1400312.html

最新回复(0)