2014-02-20 41 views
13

如果在java中創建的進程創建子進程,但之後返回,則JVM掛起,但沒有進程ID。下面當子進程仍然打開時,爲什麼Java進程從Gradle掛起?

示例應用程序(需要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); 
    } 
} 

當應用程序運行時,它會創建三個過程: 爪哇 - > CMD - >記事本 CMD立即返回,Java調用系統。退出(0),這會殺死java進程。 但是記事本仍然存在,並且在從gradle(或者eclipse)運行時,JVM掛起,直到該進程消失,而不是返回它的返回值。

因此,孩子的過程仍然活着,但父母的過程已被部分殺害,但現在被永遠擱淺。

的腳本的build.gradle重現此

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進程的ID並在關閉鉤子中查殺所有子進程?

+0

這看起來不像是對我的Gradle真的有用。你有沒有嘗試過從命令行運行你的課程? –

+1

是的。它按預期工作(正如我所料,無論如何)都是從命令行運行的。它返回退出狀態,記事本仍在運行。問題在於gradle是運行這裏建模的java進程的自動化工具,並且永遠不會返回。 – w25r

回答

2

的過程中的文檔說

默認情況下,創建的子進程沒有自己的終端或控制檯。其所有標準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

我正在管道實際違規流程的輸出流。這不是問題。在這個例子中,notepad.exe沒有輸出。只是它還活着。 – w25r

+0

您執行的流程流程如何?在你的例子中,我正在討論排幹p.getInputStream()和p。getErrorStream() –

+0

我已經闡明瞭這個例子來證明這不是問題。當這是一個問題時,通常process.waitFor()是掛起的,並且JVM線程保持活動狀態。這些都不在這裏發生。 – w25r

1

我會說this answer可能有助於獲得子進程ID和this one - 與殺死他們在Windows環境中。

希望有幫助!

+0

所以這個問題是java進程啓動了啓動記事本進程的cm​​d進程......但是隨後cmd進程消失了。這是java和記事本之間的唯一聯繫。所以你甚至不能殺死所有的子進程,因爲它不再知道notepad.exe。 – w25r