`

Java调用外部程序命令时线程阻塞问题分析

 
阅读更多

    文章参考http://www.qqread.com/java/2010/05/w493489.html

    今天要写个远程重启服务的功能,为了开发速度,暂时定为Java代码+WMIC命令的方法,简单的说,就是利用Java调用本机应用程序的方法。涉及到的 Java类有java.lang包里面的Runtime、Process、ProcessBuilder三个类,以及wmic中重启服务的命令。因为之前 也写过这方面的东西,所以很习惯性的写出了代码:

 

 

Process p = Runtime.getRuntime().exec("wmic ...");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String tmp = null;
while ((tmp = br.readline()) != null) {
  System.out.println(tmp);
}
int exitValue = p.waitfor();
 

 

  运行,结果发现程序不能退出,Debug发现程序阻塞在br.readline()中了,强制结束程序,发现重启服务的命令正常下下去了,去掉程序中获得标准输出的地方和获得返回结果的地方,命令也能正常下去,而且正常退出。

  为什么程序会阻塞呢?Google了一下,发现了大家的解释,应该也是比较权威的解释吧:每个进程都有自己的标准输入、标准输出、标准错误输出,对于某些 依赖于OS的进程,可能其输出缓冲区很小,如果不能及时的读出(标准输出、标注错误输出),将导致进程不能正常退出。我的程序中标准输出已经读了,显然原因不是这个,难道是错误输出缓冲区中的数据没有读出导致的?带着这个疑问,对程序作了一些更改:

 

ProcessBuilder pb = new ProcessBuilder("wmic",...);
pb.redirectErrorStream(true);
Process p = pb.start();
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了一下,大家的评论大多还是关于标准输出和标准错误输出,那这程序应该是没有问题了。后来在 cmd中敲入wmic的命令,发现wmic命令敲入以后会进入一个自有的提示符中,难道是因为标准输入的问题。后来又google了一下,验证了我的猜 想,果然是因为wmic进程会等待标准输入,而程序中没有处理标准输入的地方,是标准输入阻塞了进程的退出,修改代码:

 

ProcessBuilder pb = new ProcessBuilder("wmic",...);
pb.redirectErrorStream(true);
Process p = pb.start();
p.getOutputStream().close();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String tmp = null;
while ((tmp = br.readline()) != null) {
  System.out.println(tmp);
}
int exitValue = p.waitfor();
   编译运行,程序成功执行。果然是标准输入的原因。

  后来执行的过程中换了一个服务的名称,发现执行失败(能够正常退出,但是返回的结果是“无效动作”),但是同样的命令,在命令行中执行成功,而且直接适用 Runtime.exec()方法中写入整个命令也能够执行成功,难道是ProcessBuilder的错误,ProcessBuilder构造函数有两 个:

  ProcessBuilder(List<String> command)

  ProcessBuilder(String... command)

 

  找到ProcessBuilder的源代码,发现了对List<String>的解析方法:JDK将List中的所有字符串用空格连接,对 list中的每个字符串JDK先判断串中是否包含空格,如果包含空格,用双引号将该字符串引起来,再拼到前面字符串的后面(应该是为了解决路径中包含空格 的问题),可恰好Wmic命令的参数中有一段是name="ServiceName",如果ServiceName中包换空格,JDK就会把 name="service name"的外层加一个双引号,导致wmic不能解析该命令了。

  问题终于全都解决了,耗费了多半天的时间,不过收获总是有的,这里总结一下,在使用Java调用外部命令的时候,一定要注意对标准输出、标准输入和错误输 出的处理。对于一般的命令,只需要将标准输出和错误输出合并,一起读出来或者在另外的线程中读出来,而对于一些特殊的命令,还有处理标准输入。建议即使不 使用标准输入,先close了,总是不会出错了。另外,使用ProcessBuilder时要注意它的空格处理方式是否是你想要的,如果不是,就不能用 ProcessBuilder了,直接使用Runtime.exec()就好了。

    另外,如果子进程Process运行的工作目录与当前主线程的工作目录一相同,则可以用下面两种方法指定子进程Process运行的工作目录。

  ProcessBuilder.directory(new File("filepath"));

  Runtime.getRuntime().exec(command, evn, new File("filepath"));

 

 

分享到:
评论

相关推荐

    JAVA上百实例源码以及开源项目

     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...

    java开源包1

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    JAVA上百实例源码以及开源项目源代码

     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...

    java开源包8

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包4

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包11

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包101

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包6

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包9

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包5

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包10

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包3

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包2

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包7

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    Java资源包01

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    JAVA面试题最全集

    请写一个java程序实现线程连接池功能? 44.给定一个C语言函数,要求实现在java类中进行调用。 45.如何获得数组的长度? 46.访问修饰符“public/private/protected/缺省的修饰符”的使用 47.用关键字final修饰一...

    疯狂JAVA讲义

    学生提问:当我们使用编译C程序时,不仅需要指定存放目标文件的位置,也需要指定目标文件的文件名,这里使用javac编译Java程序时怎么不需要指定目标文件的文件名呢? 13 1.5.3 运行Java程序 14 1.5.4 根据...

    21天学通Java-由浅入深

    第一篇 基础篇 第1章 Java简介(精彩视频:33分钟) 21 1.1 Java的平台简介 21 1.2 安装工具包 22 1.2.1 下载JDK 22 1.2.2 安装JDK 24 1.2.3 查看与设置环境变量 25 1.2.4 JDK常用命令 27 1.2.5 Java各个目录含义 28...

Global site tag (gtag.js) - Google Analytics