wmic command executed in Java blocked

在Java執行下面的windows的wmic命令時,

wmic cpu get loadpercentage /value
wmic os get totalvisiblememorysize,freephysicalmemory /value
wmic process where(name="java.exe") get name,creationdate,workingsetsize,pagefileusage /value

遇到了從Process的InputStream中讀執行結果時,程序阻塞在讀的語句處,如下代碼所示:

 

ProcessBuilder pb = new ProcessBuilder("wmic",...);  
// pb.redirectErrorStream(true);   // 註釋代碼1
Process p = pb.start(); 
// p.getOutputStream().close();    // 註釋代碼2
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));  
String tmp = null;  
  
while ((tmp = br.readline()) != null) {    //阻塞代碼處
    System.out.println(tmp);  
}  
int exitValue = p.waitfor();

通過google,Java method calls the WMIC command提到根據操作系統的不同,每個Process的InputStream的大小不等,當InputStream沒有足夠的空間來保存執行結果時,執行結果會輸出到ErrorStream當中。但是當我把上面註釋代碼1放開之後(另外的一個方案是創建兩個線程,一個從InputStream讀取執行結果,一個從ErrorStream中讀取執行結果),程序仍然阻塞在read代碼處。

繼續google,提到了有可能因爲Process是在等待輸入結束的標誌,在上面代碼中,我們只是輸入了wmic命令,但是沒有結束輸入,所以放開上面的註釋代碼2,問題解決。終於可以得到正確的輸出了。

值得一提的是,當我們在創建的Process中先打開一個單獨的cmd窗口,再執行上面的wmic命令時,確可以得到正確的輸出結果。

 

上述代碼在Win7,Win2008上可以很好的併發執行。但是在WinXP和Win2003上併發執行時,確遇到了如下的錯誤:

Win32 Error: The process cannot access the file because it is being used by another process

 通過觀察發現,在WinXP和Win2003上執行代碼時,會生成一個臨時的TempWmicBatchFile.bat文件,因此就可以解釋上面的現象了,因爲臨時文件的訪問沒有被同步。但是如果對每個命令執行都同步這個臨時文件,當命令很多時,有可能出現大面積等待的請求。考慮到我們不需要時時得到最新的數據,因此我們對每個命令的執行結果都進行了緩存,而對命令的執行進行了同步,這樣每次來的新命令就可以先拿緩存的執行結果,然後把自己放到等到命令隊列中。這樣就有效的避免了上面的錯誤。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章