当tomcat关闭时,如何杀死由Java生成的子进程

时间:2011-11-30 12:56:42

标签: java tomcat process jvm shutdown

我已经为JIRA(一个在tomcat中运行的Web应用程序)编写了一个服务,该服务定期运行(例如1小时)。基本上,服务通过runtime.exec(command)执行系统命令并解析命令生成的输出然后用它更新Lucene索引,输出将是巨大的。

问题是:

1)如果在执行上述服务时我用shutdown.sh关闭tomcat,则java(或catalina)进程不会被杀死。 java和&子进程生存一段时间,即直到系统命令完成为止。服务处理输出。但是,服务无法更新索引,使索引处于不一致状态。

如果我在上面的服务没有运行时关闭tomcat,一切都很好。我想,this is explained here。我仍然不清楚为什么JVM不会因为上面的服务在tomcat中运行而关闭?

请注意,这是该机器上运行的唯一Java应用程序。

2)然后,如果我使用kill <pid>杀死java,那么java&amp;儿童进程被杀害与this post相矛盾。

这是因为子进程正在将输出发送到父进程(java),一旦父进程被终止,子进程就不知道在哪里发送输出并因此被杀死了?

3)我尝试使用shutdownhook解释in this post,但这对我不起作用。 shutdownhook中的代码仅在java&amp;之后执行。子过程完成了他们的工作。因此,在shutdownhook中调用process.destroy()在这里没用。

这看起来很明显,因为在我的情况下JVM仍在运行,它不会在启动它的关闭序列之前调用shutdownhooks。不知道这对另一个人有什么用处,我的意思是,当JVM关闭时,java生成的子进程怎么还在运行。

4)如果我重新启动tomcat,将生成具有不同pid的新java进程。

是否可以在关闭tomcat时以编程方式停止子进程?

如果我不清楚我的解释,请告诉我......

以下是执行系统命令的代码:

        String command = getCommand();

        File view = new File(viewPath);
        Runtime runtime = Runtime.getRuntime();
        try
        {
            final Process process = runtime.exec(command, null, view);

            StreamReader errorStreamReader = new StreamReader(process
                .getErrorStream());
            Thread errorStreamThread = new Thread(errorStreamReader);
            errorStreamThread.start();
            revisions = parseRevisionLogs(process.getInputStream());

            process.waitFor();

            process.getInputStream().close();
            process.getErrorStream().close();
            process.getOutputStream().close();
        }

3 个答案:

答案 0 :(得分:3)

除非剩下的线程标记为“守护进程”,否则JVM不会关闭。任何非守护程序用户线程必须在JVM退出之前完成。见this question。如果您的周期性任务未使用setDaemon(true)设置,则必须在JVM退出之前完成。您必须在流程开始前致电setDaemon

您应该能够将定期任务变为守护进程,但是在JVM关闭时遇到竞争条件。你可能会考虑让一个守护进程任务从进程中读取,但是有一个非守护进程任务会更新索引,这可能不会在它工作时被杀死。

您的非守护程序线程可能正在休眠,等待负载完成,并测试它是否应以volatile boolean字段或其他信号终止。

答案 1 :(得分:2)

我建议你做以下事情。

不要直接从java读取进程的输出。而是将输出重定向到文件,并在进程终止时从那里读取它。使用存储单独进程的PID的批处理文件或shell脚本包装您的命令,以便您可以单独终止此进程。现在将tomcat添加到将运行kill PID的tomcat,其中PID是单独进程的进程ID。

我相信这会有效,因为现在你的tomcat和单独的进程完全解耦了,所以没有什么能让tomcat陷入困境。关于这个过程也是如此。

祝你好运。

答案 2 :(得分:0)

你正在对进程进行waitFor()吗?

如果是这样,您可以抓住InterruptedExceptionp.destroy()