`

【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

 

 

1
0
分享到:
评论
2 楼 myumen 2015-01-23  
博主说的第三种:打开一个端口,监听端口里的命令,收到命令后调用System.exit。Tomcat用的就是这种方法。
1 楼 san_yun 2013-09-13  
应用做到平滑停止还是挺麻烦的,博主只提到了触发应用停机的入口,基本流程是:
1. kill pid
2.触发jvm的addShutdownHook。
3.如果在spring容器中,触发springbean的destroy-method回调方法。

但不同的应用场景要做到平滑停止面临不一样的问题,比如一台服务Server,不断有请求过来,如果要停止,已经执行一半的事务应该如何处理,如何平滑停止保证不会产生脏数据?期待博主能有更深入的分析。

相关推荐

    Java Service Wrapper 将你的java应用程序安装成windows系统服务

    Java Service Wrapper是一个强大的工具,它允许开发者将Java应用程序轻松地包装为Windows系统服务,以便在操作系统启动时自动启动Java程序,并能实现与系统服务相同的管理功能,如自动重启、日志记录等。这个工具...

    简单微信程序java课程设计报告.doc

    - 使用Java语言作为后台处理的主要编程语言,因为Java是Android应用程序开发的基础。 - 结合Android Studio开发环境,利用其提供的工具和库来构建用户界面和管理应用程序逻辑。 - 资料来源包括教师讲解的Java和...

    JAVA版风扇小程序

    此外,为了使风扇转动看起来更加自然,可能还应用了一些平滑动画技术,如缓动函数(easing function),使得速度变化更加平滑。 在实际编程中,为了使代码结构清晰、易于维护,可能采用了面向对象的设计原则,将...

    几个有意思的JAVA小动画程序

    Java是一种广泛使用的编程语言,尤其在开发Web应用程序和桌面应用程序方面具有强大能力。"JAVA小动画"这个压缩包文件很可能包含了一些使用Java Applet技术编写的简单动画程序,非常适合Java初学者用来学习和理解基本...

    java tomcat 监控程序

    Java Tomcat监控程序是用于确保Web应用程序持续稳定运行的重要工具。在Java开发环境中,Tomcat是一个广泛使用的开源应用服务器,特别适用于运行Java Servlets和JavaServer Pages(JSP)。为了提高系统的可靠性和稳定...

    java实现一个滚动字幕的程序

    在Java编程语言中,创建一个滚动字幕程序是一项常见的任务,尤其在开发用户界面或多媒体应用时。这个程序的核心目标是让文字在指定区域里连续滚动显示,类似于电视新闻底部的跑马灯效果。下面我们将深入探讨如何实现...

    贪吃蛇的多线程java程序

    在Java编程中实现贪吃蛇游戏时,多线程技术的应用可以使游戏更加流畅且具有实时性。以下是对这个多线程Java程序的一些详细解释。 1. **线程基础** - 在Java中,线程是程序执行的最小单位,可以同时执行多个任务。...

    Java语言程序设计的课程设计项目——利用Java实现地球系动画完整实现实例(第2部分).pdf

    项目执行有两种方式:作为应用程序和Applet。在MyEclipse中,可以直接运行项目,观察程序的运行效果。如果打算长期在MyEclipse中工作,可以考虑为Application和Applet声明包,如com.px1987.animation。这样做的好处...

    java 关于动画的一段处理程序,很精采的-java animation on the procedures for hand

    理解并掌握这些工具和概念对于开发动态、交互性强的Java应用程序至关重要。通过实践和研究如"java animation on the procedures for hand"这样的示例,开发者可以进一步提升他们的Java动画技能。

    java GUI做的抽奖转盘

    Java GUI(图形用户界面)是Java编程语言中用于创建用户交互界面的一部分,它允许开发者构建桌面应用程序,提供视觉反馈和用户交互。在这个“java GUI做的抽奖转盘”项目中,我们很可能看到一个利用Java Swing或...

    Java游戏编程初级教程

    Java提供了Java Sound API来处理音频播放,包括加载、播放、暂停和停止音效。 七、游戏对象和状态管理 游戏中的对象,如角色、敌人、道具等,都有各自的状态和行为。通过设计良好的类结构和状态机,可以有效地管理...

    心率测量java代码

    在心率测量领域,开发一款基于Java的应用程序可以为用户提供便捷的健康监测方式。通过指尖检测脉搏,软件能够分析并计算出用户的心率。在这个项目中,我们看到的是一系列反编译后的Java源代码文件,包括c.java、d....

    java3D的jar包

    Java3D是一个强大的Java库,专门用于在Java应用程序中创建和展示三维图形。它由Sun Microsystems开发,并在Java Community Process (JCP) 的JSR 23D规范下定义。这个"java3D的jar包"是Java3D库的核心组成部分,提供...

    Java-slide.rar_java sli_javaSlide_java图片幻灯片_java幻灯片播放_slide java

    理解如何正确管理和加载外部资源是Java应用程序开发的重要部分。 8. **设计模式**: 良好的代码结构可能采用了设计模式,如单例模式用于管理图片加载服务,工厂模式用于创建不同类型的特效,策略模式用于动态切换...

    Java小球撞击

    2. **Swing库**:Java的Swing库用于构建GUI应用程序。在这个项目中,我们需要使用`JFrame`来创建主窗口,`JPanel`作为小球移动的画布,以及`Graphics`类进行绘图操作。 3. **图形绘制**:利用`Graphics`类的`...

    Java动画编程优化技术探讨.pdf

    Java动画编程是计算机图形学与Java技术结合的产物,它允许开发者在Java平台上创造...总结来说,本文档对于Java动画编程技术的优化提供了宝贵的理论指导和实践建议,对开发高质量的Java动画应用程序具有重要的参考价值。

    JAVA实验字符串的滚动

    - `Applet`类是Java中用于创建可以嵌入到网页中的小型应用程序的基本类。 - 我们将继承`Applet`类,并重写其`paint`方法来绘制我们的滚动文本。 2. **字体设置**: - 通过`GraphicsEnvironment`类获取系统可用的...

    模拟时钟程序

    1. **生成应用程序框架**:使用AppWizard生成基础的应用程序框架。 2. **编辑菜单资源**:在主菜单中添加“时钟控制”菜单项,包含启动时钟、停止时钟和时间设置等子菜单项。 3. **添加消息处理函数**:利用...

    Java编写的炫酷俄罗斯方块

    7. **动画效果**:为了增加游戏的视觉吸引力,开发者可能会使用延时或帧率控制(例如使用`java.util.Timer`类)来平滑地显示方块的下落和旋转,使游戏看起来更流畅。 8. **得分系统**:每当消除一行或多行,游戏...

    java applet 连续画同心圆

    Java Applet是Java平台的一部分,允许开发者创建可以在Web浏览器中运行的小型应用程序。要创建一个Applet,你需要继承`java.applet.Applet`类或者使用JApplet(自Java 1.2版本起推荐使用),并覆盖必要的方法,如`...

Global site tag (gtag.js) - Google Analytics