温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java应用程序的平滑停止怎么实现

发布时间:2022-01-06 22:14:18 来源:亿速云 阅读:250 作者:iii 栏目:编程语言

这篇文章主要介绍“Java应用程序的平滑停止怎么实现”,在日常操作中,相信很多人在Java应用程序的平滑停止怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java应用程序的平滑停止怎么实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Java应用程序退出的触发机制有:

  1. 自动结束:应用没有存活线程或只有后台线程时;

  2. System.exit(0);

  3. kill 或 ctrl+C;

  4. kill -9 强制退出;

如何做到应用程序平滑停止

程序的退出就像关机一样,我们希望关机时平滑关机,保证所有应用程序的数据都保存了。就像现在在写得blog,希望关机的时候能被保存好到草稿箱里。

我们的的Java程序中经常有一种常驻的任务或服务,如消息消费端、服务提供者,我们期望停止也是平滑的不会出现事务执行到一半产生脏数据。

java对这块的支持是通过钩子线程实现。每个Java进程都可以注册钩子线程,钩子线程程在程序退出的前被执行(kill -9强制退出除外)。注册钩子线程代码如下:

Runtime.getRuntime().addShutdownHook(t);

我们可以在钩子线程里做一些善后数据清理等事情,以保证程序是平滑退出的。

一般服务或框架运行都要考虑其生命周期:

如spring容器的context.stop()方法。

再如线程池ExecutorService的shutdown方法,它会保证不接受新任务,并把未执行完的任务做完。

我们再设计服务的时候也要考虑到停止时的stop方法,以便于退出时由钩子线程调用。

注册了钩子线程后,程序收到退出信号后,会保持程序运行,直到钩子线程执行完毕,才把程序的所有线程停止并退出,下面示例代码可以说明这一点:

public class ShutDownTest {       public static void main(String[] args) {          //注册***个钩子          Runtime.getRuntime().addShutdownHook(new Thread() {               public void run() {                  try {                      Thread.currentThread().sleep(5000);                  } catch (InterruptedException e) {                      e.printStackTrace();                  }                  System.out.println("clean task1 completed.");              }          });          //注册第二个钩子          Runtime.getRuntime().addShutdownHook(new Thread() {               public void run() {                  try {                      Thread.currentThread().sleep(10000);                  } catch (InterruptedException e) {                      e.printStackTrace();                  }                  System.out.println("clean task2 completed");              }          });          //启动子线程          new Thread() {               public void run() {                  while (true) {                      try {                          Thread.currentThread().sleep(1000);                          System.out.println("sub thread is running");                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                  }              }          }.start();          //程序退出          System.exit(0);      }   }

程序输出:

sub thread is running  sub thread is running  sub thread is running  sub thread is running  clean task1 completed.  sub thread is running  sub thread is running  sub thread is running  sub thread is running  sub thread is running  clean task2 completed

注意点:钩子线程里只处理善后,目标是尽可能快的退出且不保证有脏数据。如果钩子线程里做过多事情,或者发生阻塞,那么可能出现kill失效,程序不能退出的情况,这是需要强制退出。

如以下程序会导致kill失效,需要强制退出,因为钩子线程阻塞了:

public class ShutDownTest {       public static void main(String[] args) {          //注册钩子          Runtime.getRuntime().addShutdownHook(new Thread() {              public void run() {                  synchronized (ShutdownFileTest.class) {                      try {                          ShutdownFileTest.class.wait();                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                  }              }          });          //启动子线程          new Thread() {              public void run() {                  while (true) {                      try {                          Thread.currentThread().sleep(1000);                          System.out.println("sub thread is running");                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                  }              }          }.start();         System.exit(0);         }   }

程序退出机制选择

触发程序退出的在前面已经提到过,但是为了停止方便、安全和优雅,一般我们推荐几种操控性更强的退出机制。常见的推荐机制有以下几种:

1.kill

在linux里用的比较多,向进程发送退出信号,java进程收到后平滑退出。

2.shutdownfile

系统创建一个shutdown file.并监听shutdown file是否存在。如果发现shutdown file不存在了,那么调用System.exit,将程序退出。

如果期望只有特定的人才能终止该程序,那么你可以给文件设定权限,这样就只有特定的人可以终止程序。

以下代码是个简单的例子:

import java.io.File;  import java.io.IOException;   public class ShutdownFileTest {       public static void main(String[] args) {          // 启动子线程          new Thread() {               public void run() {                  while (true) {                      try {                          Thread.currentThread().sleep(1000);                          System.out.println("sub thread is running");                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                  }              }          }.start();                    //启动shutdownfile监听线程          new Thread() {               public void run() {                  File shutDownFile = new File("a.shutdown");                  // create shut down file                  if (!shutDownFile.exists()) {                      try {                          shutDownFile.createNewFile();                      } catch (IOException e) {                          e.printStackTrace();                      }                  }                  // watch for file deleted then shutdown                   while (true) {                      try {                          if (shutDownFile.exists()) {                              Thread.currentThread().sleep(1000);                          } else {                              System.exit(0);                          }                      } catch (InterruptedException e) {                          e.printStackTrace();                      }                  }              }          }.start();      }   }

3.打开一个端口,监听端口里的命令,收到命令后调用System.exit。

这个似乎不常见,也比较麻烦。

4.JMX

通过JMX的mbean远程控制来实现。

在这个链接里有看到例子:how-to-stop-java-process-gracefully

到此,关于“Java应用程序的平滑停止怎么实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI