简体   繁体   English

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

[英]Why does a Java process hang from Gradle when sub-process is still open?

If a process created in java creates a sub-process, but then returns, the JVM hangs, but with no process id. 如果在java中创建的进程创建了一个子进程,但随后返回,则JVM挂起,但没有进程ID。

Example application below (requires Windows and Java 7) 下面的示例应用程序(需要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);
    }
}

When the application runs, it creates three processes: java --> cmd --> notepad cmd immediately returns and java calls System.exit(0), which kills the java process. 当应用程序运行时,它会创建三个进程:java - > cmd - > notepad cmd立即返回,java调用System.exit(0),这会终止java进程。 But notepad is still there, and, when run from gradle (or eclipse for that matter,) the JVM hangs around until that process goes away, not returning it's return value. 但是记事本仍然存在,并且,当从gradle(或eclipse)运行时,JVM会一直挂起,直到该进程消失,而不是返回它的返回值。

So the children process is still alive but the parent process has been partially killed, but is now stranded forever. 因此,子进程仍处于活动状态,但父进程已被部分杀死,但现在已永远搁浅。

The build.gradle script to reproduce this 用于重现此内容的build.gradle脚本

apply plugin: 'java'
apply plugin: 'application'
mainClassName = "SubProcessHang"

Execute 'gradle run' and get this output: 执行'gradle run'并获得此输出:

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

I know it must have something to do with how the java processes are created, but I have no idea what to do. 我知道它必须与如何创建java进程有关,但我不知道该怎么做。

What can I do short of getting the ID of the running java process and killing all sub-processes in a shutdown hook? 除了获取正在运行的java进程的ID并在关闭钩子中杀死所有子进程之外,我还能做些什么呢?

The docs for Process say 流程的文档说

By default, the created subprocess does not have its own terminal or console. 默认情况下,创建的子进程没有自己的终端或控制台。 All its standard I/O (ie stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream(). 它的所有标准I / O(即stdin,stdout,stderr)操作将被重定向到父进程,在那里可以通过使用方法getOutputStream(),getInputStream()和getErrorStream()获得的流来访问它们。 The parent process uses these streams to feed input to and get output from the subprocess. 父进程使用这些流向子进程提供输入并从子进程获取输出。 Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock. 由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。

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

Maybe your process is creating stdout or stderr output. 也许你的进程正在创建stdout或stderr输出。 Try draining the InputStream and the ErrorStream. 尝试耗尽InputStream和ErrorStream。

I would say that this answer might help with getting the sub-process IDs and this one - with killing them in Windows environment. 我想说这个答案可能有助于获取子进程ID和这个 - 在Windows环境中杀死它们。

Hope that helps! 希望有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM