Thinking In Java P550(中文版)程序代码有误

这一段时间在研究《Java编程思想》,个人认为[color=red]第550页,18.9 进程控制[/color],OSExecute类有问题(英文版是P944)。如果用书上的代码,程序一直就会处在阻塞的状态,更不用说,打印进程的输出信息了。
以下是书上的代码:
package cn.com.newocm;

/**
* 异常处理类 处理进程在执行过程中产生的错误
*
* @author zhq
*
*/
public class OSExecuteException extends RuntimeException {

private static final long serialVersionUID = 1L;

public OSExecuteException(String why) {
super(why);
}
}


package cn.com.newocm;

import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 进程控制
* @author zhq
*
*/
public class OSExecute {
public static void command(String command) {
boolean err = false;
try {
Process process = new ProcessBuilder(command.split(" ")).start();
BufferedReader results = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String s;
while ((s = results.readLine()) != null)//如果命令输入正确,此处一直阻塞
System.out.println(s);
BufferedReader errors = new BufferedReader(new InputStreamReader(
process.getErrorStream()));
while ((s = errors.readLine()) != null) {
System.err.println(s);
err = true;
}
} catch (Exception e) {
if (!command.startsWith("CMD /C"))
command("CMD /C " + command);
else
throw new RuntimeException(e);
}
if (err)
throw new OSExecuteException("Errors executing " + command);
}

public static void main(String[] args) {
command("wmic process");
}
}


上面代码执行后,没有任何反应,因为创建的进程被阻塞。原因在于,引用Java API中的原话:“[color=red]有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁[/color]”。


为了不至于出现上述问题,个人认为,需要对代码进行改进,采用多线程机制,一个线程负责读取正确信息,一个线程负责读取错误信息;在进程信息读取完毕后,应该显式的关闭进程的OutputStream。

更改后的代码:
package cn.com.newcom.runtime.exec;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
* 在Java内部执行Windows操作系统的程序
*
* @author zhq
*
*/
public class OSExecute {
public static void command(String command) {
try {
// 利用指定的操作系统程序和参数构造一个进程生成器
Process process = new ProcessBuilder(command.split(" ")).start();
// 错误的信息
StreamGobbler errorGobbler = new StreamGobbler(process
.getErrorStream(), "ERROR");
// 正确的信息
StreamGobbler outputGobbler = new StreamGobbler(process
.getInputStream(), "OUTPUT");
// 启动线程
errorGobbler.start();
outputGobbler.start();
// 关闭进程输出流
process.getOutputStream().close();
// 等待该进程执行完毕
int exitVal = process.waitFor();
System.out.println("ExitValue: " + exitVal);
} catch (Exception e) {
if (!command.startsWith("cmd /C")) {
// 只考虑了Windows 2000以上的操作系统,对于Windows 95应该是command.com /C
command("cmd /C " + command);
} else
throw new RuntimeException(e);
}
}

public static void main(String[] args) {
command("cmd /C wmic process");
}
}

/**
* 该线程负责读取进程输出的信息
*
* @author zhq
*
*/
class StreamGobbler extends Thread {
private InputStream is;
// 输出信息的类型,错误信息,还是正确信息
private String type;

StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}

public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = br.readLine()) != null)
System.out.println(type + ">" + line);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}



以上只是个人的见解,有不对的地方,还请大家指教!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值