你在問題中提供了很少的細節,所以我只能提供一個普遍的答案。
所有進程都有三個標準流:標準輸入,標準輸出和標準錯誤。標準輸入用於讀取數據,標準輸出用於寫出數據,標準錯誤用於寫出錯誤消息。當您使用Runtime.getRuntime().exec()
或ProcessBuilder
啓動外部程序時,Java將爲外部程序創建一個Process
對象,並且此Process
對象將具有訪問這些流的方法。
這些流訪問如下:
process.getOutputStream()
:返回外部程序的標準輸入。這是一個OutputStream
,因爲它是Java代碼寫入的內容。
process.getInputStream()
:返回標準輸出的外部程序。這是一個InputStream
,因爲它是Java代碼讀取的內容。
process.getErrorStream()
:返回外部程序的標準錯誤。這是一個InputStream
,就像標準輸出一樣,這是Java代碼讀取的內容。
請注意,getInputStream()
和getOutputStream()
的名稱可能會引起混淆。
您的Java代碼和外部程序之間的所有流都是緩衝。這意味着每個流都有少量內存(一個緩衝區),其中寫入程序可以寫入尚未被讀取器讀取的數據。作者不必等待讀者立即讀取其數據;它可以將其輸出保留在緩衝區中並繼續。
有兩種方式寫入緩衝區並從中讀取可掛:
- 試圖將數據寫入緩衝區時,有沒有離開的數據足夠的空間,
- 試圖讀取從一個空的緩衝區。
在第一種情況下,寫入器將通過從緩衝區中讀取數據來等待緩衝區中的空間。第二,讀者將等到數據寫入緩衝區。
您提到關閉由getOutputStream()
返回的流導致您的程序成功完成。這關閉了外部程序的標準輸入,告訴它沒有其他東西可以讀取。如果您的程序成功完成,這表明您的程序在掛起時等待更多輸入。
也許有爭議,如果你運行一個外部程序,你應該關閉它的標準輸入,如果你不需要使用它,就像你做的那樣。這告訴外部程序將不再有輸入,因此消除了等待輸入的可能性。但是,它並沒有回答你的外部程序爲何等待輸入的問題。
大多數情況下,當您使用Runtime.getRuntime().exec()
或ProcessBuilder
運行外部程序時,您並不經常使用標準輸入。通常情況下,您可以在命令行上將所需的任何輸入傳遞給外部程序,然後讀取其輸出(如果它生成的話)。
您的外部程序是否執行您所需要的操作,然後卡住,顯然等待輸入?你是否需要將數據發送到其標準輸入?如果您使用cmd.exe /k ...
在Windows上啓動進程,則即使在啓動的程序退出後,命令解釋程序也會繼續。在這種情況下,您應該使用/c
而不是/k
。
最後,我想強調,有兩個輸出流,標準輸出和標準錯誤。如果您在錯誤的時間從錯誤的流中讀取,可能會出現問題。如果您嘗試從緩衝區爲空的外部程序的標準輸出讀取數據,Java代碼將等待外部程序生成輸出。但是,如果外部程序正在將大量數據寫入其標準錯誤,它可能會填充緩衝區,然後發現自己正在等待Java代碼通過讀取緩衝區來在緩衝區中創建空間。最終的結果就是你的Java代碼和外部程序都在等待對方做某件事,例如死鎖。
只需使用ProcessBuilder
並確保您使用true
值調用其redirectErrorStream()
方法即可簡化該問題。調用此方法會將外部程序的標準錯誤重定向到其標準輸出,因此只有一個流可以讀取。
你試圖運行什麼外部程序?你可以在命令提示符/ Terminal/shell中運行這個程序嗎? – 2012-07-20 14:16:45