解决waitfor()阻塞问题
运行代码执行exe,shell这样的程序或脚本再java中需:
(1) 使用Runtime的exec()方法
(2) 使用ProcessBuilder的start()方法
Runtime和ProcessBulider提供了不同的方式来启动程序,设置启动参数、环境变量和工作目录。
但是这两种方法都会返回一个用于管理操作系统进程的Process对象。这个对象中的waitFor()是我们今天要讨论的重点。
Process的api中有如下说明:
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。 创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。
创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。
因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。
当Runtime对象调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立三个管道连接:标准输入,标准输出和标准错误流。
也就是说:如果程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitFor()这里。
多数是创建两个线程在waitFor()命令之前读出窗口的标准输出缓冲区和标准错误流的内容。
package DailyTest; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List; public class CommandUtil {
//保存进程标准输入流信息
private List<String> stdotList = new ArrayList<>();
//保存进程标准错误流信息
private List<String> errorList = new ArrayList<>(); public void executeCommand(String command){
stdotList.clear();
errorList.clear(); Process p =null;
try {
p = Runtime.getRuntime().exec(command);
//创建两个线程 分别读取输入流缓冲区和错误流缓冲区
ThreadUtil stdotThread = new ThreadUtil(stdotList,p.getInputStream());
ThreadUtil errorThread = new ThreadUtil(errorList,p.getErrorStream()); stdotThread.start();
errorThread.start(); p.waitFor();
//一直挂起,直到子进程执行结束
//返回值0表示正常退出 } catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} } public List<String> getErrorList() {
return errorList;
} public List<String> getStdotList() {
return stdotList;
}
} class ThreadUtil implements Runnable{ //属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。
private String character1 = "ISO-8859-1";
//汉子的国标码,专门用来表示汉字,是双字节编码,而英文字母和iso8859-1一致(兼容iso8859-1编码)。
// 其中gbk编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,gbk是兼容gb2312编码的。
private String character2 = "GB2312";
//最统一的编码,可以用来表示所有语言的字符,而且是定长双字节(也有四字节的)编码,包括英文字母在内。
private String character3 = "unicode";
//相比于unicode会使用更少的空间,但如果已经知道是汉字 推荐GB2312
private String character4 = "utf-8"; private List<String> list;
private InputStream inputStream; public ThreadUtil(List<String> list,InputStream inputStream){
this.list = list;
this.inputStream = inputStream;
} public void start(){
Thread thread = new Thread(this);
thread.setDaemon(true); //设置为守护线程
//定义:守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开。优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。
thread.start();
} @Override
public void run() {
BufferedReader br =null;
try {
br = new BufferedReader(new InputStreamReader(inputStream,character2));
String line =null;
while (null != (line = br.readLine())){
list.add(line);
} }catch (IOException e){
e.printStackTrace();
}finally {
try {
inputStream.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
}
package DailyTest;
import java.util.List;
public class TestCommandUtil {
//快速修改类名 shift+F6
public static void main(String args []){
CommandUtil commandUtil =new CommandUtil();
commandUtil.executeCommand("javac");
printList(commandUtil.getStdotList());
System.out.println("--------------------");
printList(commandUtil.getErrorList());
}
public static void printList(List<String> list){
for (String string : list) {
System.out.println(string);
}
}
}
这个方法确实可以解决调用waitFor()方法阻塞无法返回的问题。
问题的关键是处在输入流缓冲区那个地方,子进程的产生的输出流没有被JVM及时的读取最后缓冲区满了就卡住了。
至于能够不让子进程向输入流写入数据,是不是可以解决这个问题,还有待考证。
解决waitfor()阻塞问题的更多相关文章
- JAVA创建子进程并处理waitFor() 阻塞问题
虽然很想休息,但是想想还是要把今天学的东西记下来,不然以后再用还是新知识. 新建一个线程类读取子进程的汇报信息和错误信息,避免阻塞 class StreamGobbler extends Thread ...
- 解决session阻塞的问题
简介 对于数据库运维人员来说创建session或者查询时产生问题是常规情况,下面介绍一种很有效且不借助第三方工具的方式来解决类似问题. 最近开始接触运维工作,所以自己总结一些方案便于不懂数据库的同事解 ...
- 解决一阻塞语句CPU直降15%
原本只是部署作业获取数据库中阻塞语句,中午测试汇集阻塞数据,发现某一服务器写入386行,而其他服务器只写入几行.登录对应服务器查看详细信息,发现有四个时间点分别写入100来行记录对于第一行:会话183 ...
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
下面的图片是我使用firefox和chrome浏览百度首页时候记录的http请求 下面是firefox: 下面是chrome: 在浏览百度首页前我都将浏览器的缓存全部清理掉,让这个场景最接近第一次访问 ...
- 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor
开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...
- “惊群”,看看nginx是怎么解决它的
在说nginx前,先来看看什么是“惊群”?简单说来,多线程/多进程(linux下线程进程也没多大区别)等待同一个socket事件,当这个事件发生时,这些线程/进程被同时唤醒,就是惊群.可以想见,效率很 ...
- IO之同步、异步、阻塞、非阻塞 (2)
[原创链接: http://www.smithfox.com/?e=191, 转载请保留此声明, 谢谢! ] I/O Model 是一个很大的话题, 也是一个实践性很强的事情, 网上有各种说法和资料, ...
- [Python]再学 socket 之非阻塞 Server
再学 socket 之非阻塞 Server 本文是基于 python2.7 实现,运行于 Mac 系统下 本篇文章是上一篇初探 socket 的续集, 上一篇文章介绍了:如何建立起一个基本的 sock ...
- Js中for循环的阻塞机制
Js阻塞机制,跟Js引擎的单线程处理方式有关,每个window一个JS线程.所谓单线程,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码. 由于浏览器是事件驱动的(Event driven) ...
随机推荐
- HDwiki 源代码 - 互动百科开源
昨日3.15,在曝光的企业中出现了一家让我好奇的企业(互动百科),一直不敢想百科能独立出来做成一家公司.出于对网站的好奇,今日进入该网站,惊讶的是此公司已经上市(股票代码:835799),在网站的底部 ...
- 学习pytho第l六天 常用字符串用法
name='my name is dream' print(name.capitalize())#首字母大写 print(name.count(‘’a‘’))#判断字符串里有多少个a print(na ...
- stm32 flash和sram
FLASH是用来存储程序的,SRAM是用来存储程序运行中的中间变量
- c语言——字符串
char str[] = "http://c.biancheng.net"; char str[] = "http://c.biancheng.net"; ch ...
- BFS:胜利大逃亡
解题心得: 1.水题,主要主意好一个点就好. 2.注意x.y.z坐标的选取就好. 题目: Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会. 魔王住在一个城堡里,城 ...
- Asp.net Mvc Action重定向总结
摘自博客园 程晓晖 [HttpPost] public ActionResult StudentList( string StudName, string studName, DateT ...
- Java面向对象---面向对象
程序的发展历程:面向过程-->面向对象 面向过程:不去想怎么做,边做边看 面向对象:先想好怎么做,然后再做 修饰符(访问权限) 访问级别 访问控制修饰符 同类 同包 子类 不同的包 公开 pub ...
- this.$router 和this.$route 的区别
1. this.$router: 表示全局路由器对象,项目中通过router路由参数注入路由之后,在任何一个页面都可以通过此方法获取到路由器对象,并调用其push(), go()等方法: 2. thi ...
- Leetcode 623.在二叉树中增加一行
在二叉树中增加一行 给定一个二叉树,根节点为第1层,深度为 1.在其第 d 层追加一行值为 v 的节点. 添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N,为 N 创 ...
- c++ STL sort struct comp
详细解说 STL 排序(Sort) http://www.cppblog.com/mzty/archive/2005/12/15/1770.html 详细解说 STL 排序(Sort) 作者Winte ...