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文件,因此就可以解释上面的现象了,因为临时文件的访问没有被同步。但是如果对每个命令执行都同步这个临时文件,当命令很多时,有可能出现大面积等待的请求。考虑到我们不需要时时得到最新的数据,因此我们对每个命令的执行结果都进行了缓存,而对命令的执行进行了同步,这样每次来的新命令就可以先拿缓存的执行结果,然后把自己放到等到命令队列中。这样就有效的避免了上面的错误。

 

你可能感兴趣的:(command)