Подтвердить что ты не робот

Почему процесс Java зависает от Gradle, когда подпроцесс все еще открыт?

Если процесс, созданный в java, создает подпроцесс, но затем возвращается, JVM зависает, но без идентификатора процесса.

Пример приложения ниже (требуется 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 (или затмения, если на то пошло) JVM зависает до тех пор, пока этот процесс не исчезнет, ​​а не вернет возвращаемое значение.

Итак, процесс детей все еще жив, но родительский процесс частично убит, но теперь он застрял навсегда.

Создайте файл script, чтобы воспроизвести этот

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

Выполнить 'gradle запустить' и получить этот вывод:

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

Я знаю, что это должно иметь какое-то отношение к тому, как создаются Java-процессы, но я не знаю, что делать.

Что я могу сделать, не получив идентификатор запущенного Java-процесса и убив все подпроцессы при завершении работы?

4b9b3361

Ответ 1

Документы для процесса говорят

По умолчанию созданный подпроцесс не имеет собственного терминала или консоли. Все его стандартный ввод/вывод (то есть стандартный ввод, стандартный вывод, STDERR) операция будет перенаправлена ​​на родительский процесс, где они могут быть доступны с помощью потоков, полученных с помощью методов getOutputStream(), getInputStream(), и getErrorStream(). Родительский процесс использует эти потоки для подачи ввода и получения вывода из подпроцесса. Поскольку некоторые собственные платформы обеспечивают ограниченный размер буфера для стандартных потоков ввода и вывода, неспособность быстро записать входной поток или прочитать выходной поток подпроцесса, может привести к блокировке подпроцесса или даже к взаимоблокировке.

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

Возможно, ваш процесс создает вывод stdout или stderr. Попробуйте слить InputStream и ErrorStream.

Ответ 2

Я бы сказал, что этот ответ может помочь получить идентификаторы подпроцесса и этот - с их убийством в среде Windows.

Надеюсь, что это поможет!