我已经为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();
}
答案 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()吗?
如果是这样,您可以抓住InterruptedException
和p.destroy()