2017-10-07 81 views
0

我已经在网上搜索,而process.waitFor() never returns这个问题表明它的stdout或stderr没有被读取的进程通常是一个问题。Process.waitFor即使stdout和stderr被读取也会挂起

我们使用ProcessBuilderredirectOutputredirectError实现这一目标,我想我们应该是在安全方面,看看我们用它来执行过程如下方法:

public static void execute(String directory, long timeout, File out, File err, String... command) throws InterruptedException, IOException { 
    LOGGER.log(Level.INFO, String.format("executing command %s (%s)", Arrays.toString(command), timeout > 0 ? String.format("timeout = %,d[ms]", timeout) : "no timeout")); 
    ProcessBuilder builder = new ProcessBuilder(); 
    builder.directory(new File(directory)); 
    builder.command(command); 
    builder.redirectOutput(out); 
    if(out == err) { 
     builder.redirectErrorStream(true);   
    } else { 
     builder.redirectError(err); 
    } 
    long time = System.currentTimeMillis(); 
    Process process = builder.start(); 
    try { 
     LOGGER.log(Level.FINE, "waiting for process"); 
     boolean exited = process.waitFor(timeout, TimeUnit.MILLISECONDS); 
     if(!exited) { 
      LOGGER.log(Level.WARNING, "timeout reached, trying to destroy ..."); 
      exited = destroy(silent, process); // Helper method to destroy processes 
     } 
     long duration = System.currentTimeMillis() - time; 
     int exitValue = process.exitValue(); 
     LOGGER.log(Level.INFO, "execution finished in " + duration + "[ms] => " + exitValue); 
    } catch (InterruptedException | Error | RuntimeException e) { 
     LOGGER.log(Level.SEVERE, "execution failed", e); 
     throw e; 
    } 
} 

然而,问题是,它挂起在process.waitFor(timeout, TimeUnit.MILLISECONDS)调用,即使过程应该很容易在超时内完成。

测井输出是

Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute 
INFO: executing command [java, -Xmx8G, -XX:+UseG1GC, -XX:+CrashOnOutOfMemoryError, -jar, MetricCalc.jar] (timeout = 14,400,000[ms]) 
Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute 
FINE: waiting for process 

(认识到,没有execution finished线尚未写入)

err文件读取

... Things we write to std.err ... 
Finished Metrics 

和MetricCalc的主要方法如下所示

public static void main(String[] args) { 
    .... do some stuff ... 
    System.err.println("Finished Metrics"); 
} 

这表明读取工作正常,Java程序的最后一行已经执行并且进程应该终止。

任何人有一个想法,为什么进程不会终止/它仍然挂在Process.waitFor()

+1

*“......并且该流程应该已经终止。”* - 假定子流程按照您的预期工作。检查子进程是否实际终止;例如使用“ps -efl”或类似的。 –

+0

@StephenC:我仍然可以使用'ps -efl | grep“java -Xmx8G”',表示它没有终止。 然而,我不知道为什么这是这样的情况,因为MetricCalc的最后一行代码(作为进程运行的Java程序)已经执行... –

+1

哦,它刚刚出现在我的脑海里:可能是MetricCalc有一些非deamon线程正在运行,从而阻止应用程序终止...我将不得不测试这... –

回答

0

这不是Process.waitFor()的问题,而是过程终止的问题。

开始使用的java应用程序使用了一个ExecutorService,它没有正确地击落并且让僵尸线程活着,从而阻止了进程终止。

添加executorService.shutdown()解决了问题,应用程序现在按预期终止。