`
walsh
  • 浏览: 429391 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

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

    博客分类:
  • java
阅读更多
  这一段时间在研究《Java编程思想》,个人认为第550页,18.9 进程控制,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中的原话:“有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁”。

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


  以上只是个人的见解,有不对的地方,还请大家指教!




  
  
1
2
分享到:
评论
2 楼 暗蓝幽谷 2013-03-14  
依旧使用BufferedReader实现,不能解决“子进程阻塞,甚至死锁”的问题
1 楼 Arron.li 2010-06-03  
不错,领教了

相关推荐

Global site tag (gtag.js) - Google Analytics