当子进程仍处于打开状态时,为什么Java进程会从Gradle挂起?

时间:2014-02-20 20:35:33

标签: java process jvm gradle subprocess

如果在java中创建的进程创建了一个子进程,但随后返回,则JVM挂起,但没有进程ID。

下面的示例应用程序(需要Windows和Java 7)

import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.Files;

public class SubProcessHang {

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "start", "notepad.exe");
        File output = Files.createTempFile("output", "txt").toFile();
        builder.redirectError(Redirect.to(output));
        builder.redirectOutput(Redirect.to(output));
        Process process = builder.start();
        process.waitFor();
        int exitValue = process.exitValue();
        System.out.println("Process exit value:: " + exitValue);
        System.out.println("Output file length:: " + output.length());
        System.exit(exitValue);
    }
}

当应用程序运行时,它会创建三个进程: java - > cmd - >记事本 cmd立即返回并且java调用System.exit(0),这会终止java进程。 但是记事本仍然存在,并且,当从gradle(或eclipse)运行时,JVM会一直挂起,直到该进程消失,而不是返回它的返回值。

因此,子进程仍处于活动状态,但父进程已被部分杀死,但现在已永远搁浅。

用于重现此

的build.gradle脚本
apply plugin: 'java'
apply plugin: 'application'
mainClassName = "SubProcessHang"

执行'gradle run'并获得此输出:

C:\HangDemo>gradlew run
:compileJava
:processResources UP-TO-DATE
:classes
:run
Process exit value:: 0
Output file length:: 0
> Building 75% > :run

我知道它必须与如何创建java进程有关,但我不知道该怎么做。

在获取正在运行的java进程的ID并在关闭钩子中终止所有子进程时,我能做什么?

2 个答案:

答案 0 :(得分:3)

流程文档说

  

默认情况下,创建的子进程没有自己的终端或控制台。它的所有标准I / O(即stdin,stdout,stderr)操作将被重定向到父进程,在那里可以通过使用方法getOutputStream(),getInputStream()和getErrorStream()获得的流来访问它们。父进程使用这些流向子进程提供输入并从子进程获取输出。由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。

http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html

也许你的进程正在创建stdout或stderr输出。尝试排空InputStream和ErrorStream。

答案 1 :(得分:1)

我会说this answer可能有助于获取子流程ID和this one - 在Windows环境中杀死它们。

希望有所帮助!