Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在tomcat关闭时杀死Java生成的子进程_Java_Tomcat_Process_Jvm_Shutdown - Fatal编程技术网

如何在tomcat关闭时杀死Java生成的子进程

如何在tomcat关闭时杀死Java生成的子进程,java,tomcat,process,jvm,shutdown,Java,Tomcat,Process,Jvm,Shutdown,我为JIRA(一个在tomcat中运行的web应用程序)编写了一个服务,它定期运行(比如1小时)。基本上,服务通过runtime.exec(command)执行一个系统命令,并解析命令生成的输出,然后用它更新Lucene索引,输出将是巨大的 问题是: 1) 如果在执行上述服务时使用shutdown.sh关闭tomcat,则不会终止java(或catalina)进程。java和子进程都存在一段时间,也就是说,直到系统命令完成&服务处理输出。但是服务无法更新索引,使索引处于不一致的状态 如果在上述服

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

问题是:

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

如果在上述服务未运行时关闭tomcat,则一切正常。我想。我仍然不清楚为什么JVM不会关闭,因为上面的服务正在tomcat中运行

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

2) 然后,如果我使用
kill
杀死java,java和子进程都会被杀死,这与

这是因为子进程正在向父进程(java)发送输出,一旦父进程被终止,子进程就不知道向何处发送输出,因此被终止

3) 我试着按解释使用,但这对我不起作用。
shutdownhook
中的代码只有在java和子进程完成工作后才能执行。因此,在shutdownhook中调用
process.destroy()
,在这里是没有用的

这似乎很明显,因为在我的例子中JVM仍然在运行,所以它不会调用shutdownhooks,直到它开始它的关闭序列。我不知道这对另一个人是如何工作的,我的意思是,为什么java产生的子进程在JVM关闭时仍在运行

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();
        }
您正在对流程执行waitFor()操作吗


如果是这样的话,您可以捕获到中断异常,并执行
p.destroy()

我建议您执行以下操作

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

我相信这会起作用,因为现在您的tomcat和单独的进程完全解耦了,所以没有什么会让tomcat关闭。过程也是如此


祝你好运。

除非剩下的线程被标记为“守护进程”,否则JVM不会关闭。任何非守护进程用户线程都必须在JVM退出之前完成。看见如果没有使用
setDaemon(true)
设置定期任务,则必须在JVM退出之前完成这些任务。在进程开始之前,必须调用
setDaemon

您应该能够使您的定期任务成为守护进程,但是JVM关闭时确实存在争用条件。您可以考虑在进程中读取一个守护进程任务,但是拥有一个非守护进程任务,可以更新索引,该索引在工作时可能不会被杀死。
然后,非守护进程线程可能正在休眠,等待加载完成,并测试它是否应以
volatile boolean
字段或其他信号终止。

能否显示定期任务是如何创建的?上述代码块将定期执行,由哪个线程执行该代码?主线?那么我的答案就站得住脚了。进程没有停止的原因是主线程不是守护进程线程,它正在从进程中读取数据。您需要在守护进程线程中运行该处理,并且在更新索引时小心它是否被终止。或者你可以做一些类似于@AlexR answer的事情,然后处理一个文件。这个解释让我想到了实际发生的事情。。。将进行一些实验,然后返回。在接收并解析输出之前,程序不会向索引写入任何内容。似乎将系统命令作为守护进程运行可以解决这个问题,但我不知道如何将进程作为守护进程,
setDaemon(true)
用于线程?是的,您需要生成另一个线程,并在它启动之前调用
setDaemon(true)
。然后,您的main需要监听tomcat的关闭