ITPub博客

首页 > > > Linux系统下如何优雅地关闭Java进程?

Linux系统下如何优雅地关闭Java进程?

作者:u_453e1a12781dea 时间:2019-07-26 16:31:43 0 删除 编辑

点击▲关注 “CU技术社区”   给公众号标星置顶

更多精彩 第一时间直达

前言


Linux系统下如何kill掉一个后台Java进程,相信童鞋们都知道如何操作。首先使用ps命令查找该Java进程的进程ID,然后使用kill命令进行杀掉。命令如下:

(1)ps查进程ID

[user@data2 ~]$ ps -ef | grep Test

user   20950 20809  0 21:30  pts/1    00:00:00 java -jar Test.jar

user   21030 20996  0 21:30 pts/2    00:00:00 grep Test

(2)kill杀进程

[user@data2 ~]$ kill -9 20950

再使用ps命令查该进程,发现进程Test.jar已经被杀掉。使用“kill -9  $pid”杀Java进程,干净利落。但该方法是不是结束Java后台进程的较好方法呢? 


场景

思考下面的场景:

“开发一个Java后台程序,其功能是不停地扫描Linux系统下的某个ftp目录。如果有文件,就经过数据转换写入到数据库中;如果没有文件,就sleep一秒钟。ftp目录下的文件不断地上传,Java程序处理完一个文件,就将该文件移到备份目录下面。”

该场景涉及Java程序进行文件打开、文件读取、文件备份、数据库连接、数据库写入等操作。因为文件句柄和数据库连接在Linux系统中是有限的资源,所以文件和数据库操作完成,需要进行关闭。

如果用户直接使用“kill -9”杀掉一个后台正在读取文件并写入数据库的Java进程。那么有可能文件和数据库连接没有正确关闭,而且数据文件也没有标识是否处理完成,或处理到哪个位置。

 

应用


近日在处理分布式消息Kafka的消息读取的工作,同样面临着上述场景的问题。如果读取了一条消息,在处理该消息之前进程被用户强行杀掉。那么该条消息就丢失了,既不在消息队列,也不在数据库或本地文件中。所以需要让后台Java进程在被杀的时候得到通知,这样就能安排好进程的“后事”。

 

Java中要得到kill信号通知,需要继承自“SignalHandler”类。完整实现代码如下:

import sun.misc.Signal;

import sun.misc.SignalHandler;

 

publicclass Engine implements SignalHandler { 

    privateboolean beKilling =false;

   

    publicstaticvoid main(String[] args){

        Engine signalHandler =new Engine();

        Signal.handle(new Signal("TERM"), signalHandler);  // kill -15

        Signal.handle(new Signal("INT"), signalHandler);    // Ctrl+c

        Signal.handle(new Signal("USR2"), signalHandler);  // kill -12     

       

        String zookeeper ="host1:2181,host2:2181,host3:2181";

        String groupId ="gp01";

        String topic ="test";

        KafkaConsumer kc =new KafkaConsumer(zookeeper, groupId, topic);

 

        //对读到的每一条kafka消息做处理

        while(!signalHandler.beKilling && kc.hasNext()){

            byte[] data = kc.getNext();

            //转为String类型

            String res=new String(data);    

            //消息处理逻辑               

            ProcessData d =new ProcessData();

            d.processingMessage(res);

        }    

       

        System.out.println("bye!");          

    }

 

    @Override

    publicvoid handle(Signal arg0){

        // TODO Auto-generated method stub

        beKilling =true;

    }

       

}

说明:

(1)需要引用sun.misc的两个类:Signal和SignalHandler;

(2)添加一个变量bKilling用于标识该进程是否正在被杀,如果是,则跳出循环不在接收Kafka消息;

(3)一般接收“kill -15”的信号。

 

在eclipse开发环境中,引用sun.misc会报找不到类问题,其实该包在rt.jar包中。需要配置一下IDE,忽略掉Signal相关的错误和警告,如下图所示:


如果尝试响应其他kill信号,运行程序时会报如下错误:

[user@data2 test]$ java -jar Test.jar

Exception in thread "main"  java.lang.IllegalArgumentException: Signal  already used by VM or OS: SIGKILL

        at  sun.misc.Signal.handle(Signal.java:166)

        at  TestSignal.main(TestSignal.java:12)

 


进程的启动与关闭


Java后台进程启动和关闭

启动:

[user@data2 test]$ nohup java  -jar Test.jar &

 查看日志:

[user@data2 test]$ more nohup.out

running ......

running ......

…

 查看进程:

[user@data2 test]$ ps -ef | grep Test.jar

unicom   28005 27711  0 22:24  pts/0    00:00:00 java -jar Test.jar

unicom   28062 27711  0 22:24 pts/0    00:00:00 grep Test.jar

 关闭进程:

[user@data2 test]$ kill -15  28005

 查看日志:

[user@data2 test]$ more nohup.out

running ......

…

running ......

TERM is recevied.

running ......

[1]+  Done                    nohup java -jar Test.jar

 


附录


在以下场景中需要使用SignalHandler来响应kill信号:

(1)文件操作;

(2)数据库操作;

(3)网络连接;

(4)循环处理的消息、数据记录等。

END

由ITPUB社区主办的第11届中国系统架构师大会(SACC2019)隆重启动,本届大会继续延用四大主线并行的演讲模式,设置业务系统架构设计、大数据平台架构设计、数字化转型实践三大主线和微服务、开源架构设计、云原生等分线,共1个主会场,20个技术专场,100+来自互联网、金融、制造业、电商等领域嘉宾。请点击【阅读原文】进入大会官网。


你「在看」吗?

点击进入 SACC2019 大会官网~

原文作者:;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-07-17

  • 博文量
    1982
  • 访问量
    17885