`

Java调用外部程序技巧

 
阅读更多
http://www.yankay.com/java%E8%B0%83%E7%94%A8%E5%A4%96%E9%83%A8%E7%A8%8B%E5%BA%8F%E6%8A%80%E5%B7%A7/

Process process = Runtime.getRuntime().exec(cmd);
process.waitfor();

   

如果直接在Shell中调用这个程序,程序会很快结束,不会僵死。

为什么会堵塞呢,原因是当调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立3个管道连接,标准输入,标准输出和标准错误流。假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取,数据会暂时缓冲在Linux的缓冲区,缓冲区满后该程序将无法继续写数据,会僵死,所以Java程序就会僵死在waitfor(),永远无法结束。

解决办法就是增加两个线程,一个线程负责读标准输出流,另一个负责读标准错误流,这样子数据就不会积压在缓冲区,程序就能够顺利运行。


import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*java调用外部命令处理.
*/
public class ProcessUtil {
	private static final int DEFAULT_BUFFER_SIZE = 1024;
	private static Log log = LogFactory.getLog(ProcessUtil.class);

	private InputStream in;

	private OutputStream out;
	private OutputStream err;

	public ProcessUtil(OutputStream out, OutputStream err, InputStream in) {
		if (out == null) {
			out = new NullOutputStream();
		}
		if (err == null) {
			err = new NullOutputStream();
		}
		this.out = out;
		this.err = err;
		this.in = in;

	}

	public int process(String cmd, String[] envp, File dir) throws IOException,
			InterruptedException {
		Process p = Runtime.getRuntime().exec(cmd, envp, dir);
		return process(p);
	}

	public int process(String[] cmdarray, String[] envp, File dir)
			throws IOException, InterruptedException {
		Process p = Runtime.getRuntime().exec(cmdarray, envp, dir);
		return process(p);
	}

	private int process(Process p) throws IOException, InterruptedException {
		try {
			OutputStream pin = p.getOutputStream();

			StreamGobbler outg = new StreamGobbler(p.getInputStream(), out);
			StreamGobbler errg = new StreamGobbler(p.getErrorStream(), err);

			outg.start();
			errg.start();

			if (in != null) {
				byte[] inBuf = new byte[DEFAULT_BUFFER_SIZE];
				int inN = 0;
				while (-1 != (inN = in.read(inBuf))) {
					pin.write(inBuf, 0, inN);
				}
				pin.flush();
			}

			int code = p.waitFor();
			outg.join();
			errg.join();
			return code;
		} finally {
			closeQuietly(p.getOutputStream());
			closeQuietly(p.getInputStream());
			closeQuietly(p.getErrorStream());
		}

	}

	private void closeQuietly(Closeable closeable) {
		try {
			if (closeable != null)
				closeable.close();
		} catch (Exception e) {
			log.warn("close error", e);
		}
	}

}

class StreamGobbler implements Runnable {
	private static final int DEFAULT_BUFFER_SIZE = 1024;
	private static Log log = LogFactory.getLog(StreamGobbler.class);

	private InputStream is;
	private OutputStream os;
	private Thread thread;

	public StreamGobbler(InputStream is, OutputStream os) {
		this.is = is;
		this.os = os;
	}

	public void start() {
		thread = new Thread(this);
		thread.setDaemon(true);
		thread.start();
	}

	public void run() {
		try {
			byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
			int n = 0;
			while (-1 != (n = is.read(buf))) {
				os.write(buf, 0, n);
			}
			os.flush();
		} catch (Exception ex) {
			log.warn("stream error", ex);
		}
	}

	public void join() throws InterruptedException {
		thread.join();
	}

}

class NullOutputStream extends OutputStream {

	public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream();

	@Override
	public void write(byte[] b, int off, int len) {
	}

	@Override
	public void write(int b) {
	}

	@Override
	public void write(byte[] b) throws IOException {
	}

}
分享到:
评论

相关推荐

    Java基于Runtime调用外部程序出现阻塞的解决方法

    主要介绍了Java基于Runtime调用外部程序出现阻塞的解决方法,是一个非常实用的技巧,需要的朋友可以参考下

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

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

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

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java 编程入门思考

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    Java初学者入门教学

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    java联想(中文)

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    第1章 让自己的第一个Java程序跑起来 2 教学视频:19分钟 1.1 想要用Java改变这个世界吗? 2 1.1.1 Java有什么优势? 2 1.1.2 Java在哪儿? 3 1.2 准备好开始Java之旅 3 1.2.1 下载JDK 4 1.2.2 安装JDK 5 ...

    疯狂JAVA讲义

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

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    第1章 让自己的第一个Java程序跑起来 2 教学视频:19分钟 1.1 想要用Java改变这个世界吗? 2 1.1.1 Java有什么优势? 2 1.1.2 Java在哪儿? 3 1.2 准备好开始Java之旅 3 1.2.1 下载JDK 4 1.2.2 安装JDK 5 ...

    JAVA_Thinking in Java

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    Thinking in Java简体中文(全)

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    Thinking in Java 中文第四版+习题答案

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴板 13.18 可视编程和 ...

    JAVA_Thinking in Java(中文版 由yyc,spirit整理).chm

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    Think in Java(中文版)chm格式

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17...

    21天学通Java-由浅入深

    28 1.3 程序开发过程 29 1.4 编码规范 29 1.5 HelloWorld:第一个Java程序 30 1.5.1 编写程序代码 30 1.5.2 编译程序代码并运行 30 1.5.3 注意事项 31 1.6 使用Eclipse集成开发工具开发 32 1.7 综合练习 32 1.8 小结...

    Thinking in Java(中文版 由yyc,spirit整理).chm

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    Java虚拟机

    增加了大量处理各种常见JVM问题的技巧和最佳实践;增加了若干与生产环境相结合的实战案例;对第1版中的错误和不足之处的修正;等等。 第2版不仅技术更新、内容更丰富,而且实战性更强。全书共分为五大部分,围绕...

Global site tag (gtag.js) - Google Analytics