Process 缓存区死锁

在开发的过程中,有时候会使用JAVA Runtime.exec() 方式运行某条命令或脚本,而在很大的情况下会出现 Process 缓存区死锁,为什么会出现死锁。JDK 开发文档说得很清楚:有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。 


明白产生死锁的原因后,就要如何快速清除缓存,我们一般的做法是先读取完标准输出流然后再读取错误输出流,这样就容易造成进程阻塞,而网上很多文章是使用两个线程,同时处理标准输出流和错误输出流,感觉上好像不错,但是代码写得不太酷,其实造成进程阻塞的原因不应该是我们JAVA要处理的,所以我们应该交给要运行的脚本或者命令处理。

这里以执行windows CMD为例子。


CMD有多个输出,如STDOUT 和 STDERR,对应的是getInputStream() 和 getErrorStream(),而我们要做的是把错误输出和标准输出合并即可,在CMD命令中可以使用“2>&1”使错误输出重定向标准输出,这样就可以代码中直接使用getInputStream()而不用使用getErrorStream(),避免Process 缓冲区死锁。例如,CMD命令

cmd.exe /E:NO /c %s 2>&1

关于CMD重定向的内容,请移步到 http://www.cnblogs.com/xiongjiaji/articles/2445539.html


下面是完整的代码:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class Cmd {
	
	private static final String TAG = Cmd.class.getSimpleName();
	
	private static final String CODE_TYPE = "UTF-8";
	
	private static final String COMMAND = "cmd.exe /E:NO /c %s 2>&1";

	public static String executeCmd(String cmd) {
		
		StringBuilder stringBuilder = new StringBuilder();
		BufferedInputStream input = null;
		ByteArrayOutputStream outputStream = null;
		Process pro = null;
		try {
			
			outputStream = new ByteArrayOutputStream();
			byte[] data = new byte[4 * 1024];
			int index = -1;
			
			String cmdStr = String.format(COMMAND, cmd);
			pro = Runtime.getRuntime().exec(cmdStr);
			input = new BufferedInputStream(pro.getInputStream());
			
			while ((index = input.read(data)) != -1) {
				outputStream.write(data, 0, index);
			}

			byte[] msgData = outputStream.toByteArray();
			if (msgData != null) {
				String msg = new String(msgData, CODE_TYPE);
				stringBuilder.append(msg);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
//			Log.v(TAG, "executeCmd error");
		} finally {
			closeOutPutStream(outputStream);
			closeInputStream(input);
			closeProcess(pro);
		}
		
		return stringBuilder.toString();
		
	}
	
	private static void closeProcess(Process pro) {
		if (pro != null) {
			
			try {
				if (pro.exitValue() == 0) {
					pro.destroy();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
	}
	
	private static void closeInputStream(InputStream inputStream) {
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	private static void closeOutPutStream(OutputStream outputStream) {
		if (outputStream != null) {
			try {
				outputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}


转载于:https://my.oschina.net/u/3368992/blog/861869

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值