将外部进程作为非阻塞Java运行

时间:2013-08-23 06:42:46

标签: java multithreading tomcat

我正在使用JUnit来运行许多需要运行外部服务器(tomcat)的测试。我目前正在使用以下代码启动tomcat。

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Runtime.getRuntime().exec("{path to tomcat}/bin/startup.bat");
            } catch (IOException exception) {
            }
        }
    });
    thread.setDaemon(true);

当所有测试都完成时,问题就出现了,JVM挂起等待tomcat关闭。如果我手动关闭tomcat,JVM会按预期关闭。

有没有办法运行tomcat,这样一旦所有测试完成(所有其他线程结束),JVM都不会被阻塞并关闭?

3 个答案:

答案 0 :(得分:1)

您需要清空进程中的输入流,否则当填充缓冲区大小时它会“很奇怪”。假设p是.exec()返回的进程:

BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String in;
while ((in = br.readLine()) != null);

您可以更改while循环以添加{}并实际打印tomcat输出(如果您愿意),但实际上您只需要清空缓冲区。

答案 1 :(得分:1)

在这种情况下,结束用于执行startup.bat批处理脚本的线程不会结束tomcat服务器。解决方案:


简短说明:

您需要执行shutdown.bat来停止tomcat。


长解释:

如果您查看startup.bat56,您会看到脚本运行命令call "%EXECUTABLE%" start %CMD_LINE_ARGS%%EXECUTABLE%设置在38行:set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"。如果您查看catalina.bat,您会看到在设置一些标准变量并检查参数后,在行242if ""%1"" == ""start"" goto doStart)中,它会跳转到:doStart,位于279行的_EXECJAVA对参数进行了一些改变,并将start [...]设置为%_EXECJAVA%它最终执行start内的任何内容。在开始的情况下,这将涉及bin命令。正如您从this documentation of the start command所见:

  

启动程序,命令或批处理脚本(在新窗口中打开。)

基本上你正在开始的过程是运行脚本,启动另一个程序然后结束,自动结束您的流程并允许线程完成。事实上,您无法直接控制tomcat,只能使用 Thread thread = new Thread(new Runnable() { @Override public void run() { try { Runtime.getRuntime().exec("{path to tomcat}/bin/shutdown.bat"); } catch (IOException exception) { } } }); 目录中的脚本。


结论:

因此,在程序结束时执行以下操作应该很容易(您可以使用关闭挂钩):

startup.bat

所以你运行shutdown.bat启动tomcat,{{1}}结束它。

很抱歉回答了一个老问题。

答案 2 :(得分:0)

即使您无法使用@Xabster解决问题,还有一件事需要将错误流重定向到输入流,就像这样

ProcessBuilder processBuilder = new ProcessBuilder(prepareCommand(table));
ProcessBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
BufferedReader stream = new BufferedReader(new nputStreamReader(process.getInputStream()));
String readLine = null;
while((readLine = stream.readLine()) != null){
    // you can do anything you want with what you read from stream
}