解决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) ...
随机推荐
- 如何用eclipse运行导入的maven项目
1.配置jdk系统环境变量.找到安装的jdk的安装目录,新建系统环境变量,变量名为JAVA_HOME(作为一个引用),变量值为该路径. 找到Path,将%JAVA_HOME%/bin; 添加到变量值的 ...
- python中函数返回多个值
用ipython运行情况如下: # 新建一个函数 In [1]: def nums(): ...: a = 11 ...: b = 22 ...: c = 33 ...: return [a,b,c] ...
- django之media配置
一.没有配置Media avatar = models.FileField(upload_to='avatars/', default='/avatars/default.png') # 储存头像的m ...
- Leetcode 106. 从中序与后序遍历序列构造二叉树
题目链接 https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/descri ...
- Asp.net自定义控件开发任我行(附1)-属性一览众山小
元数据属性应用于服务器控件及其成员,从而提供由设计工具.ASP.NET 页分析器.ASP.NET 运行库以及公共语言运行库使用的信息.当页开发人员在可视化设计器中使用控件时,设计时属性能改进开发人员的 ...
- Asp.net自定义控件开发任我行(2)-TagPrefix标签
摘要 前面我们已经做了一个最简单的TextBox的马甲,此篇文章,我们来讲讲自定义控件的标签.大家可能看到了上一篇中拖放进来的代码是 <cc1:TextEdit ID="TextEdi ...
- Win 10激活
Win10专业版激活(亲测有效) 来源:http://jingyan.baidu.com/article/295430f1ce2e880c7e0050ff.html 1.首先,我们先查看一下Win10 ...
- Leetcode 521.最长特殊序列I
最长特殊序列 I 给定两个字符串,你需要从这两个字符串中找出最长的特殊序列.最长特殊序列定义如下:该序列为某字符串独有的最长子序列(即不能是其他字符串的子序列). 子序列可以通过删去字符串中的某些字符 ...
- [oldboy-django][6其他]学习django网站推荐
http://www.cnblogs.com/holbrook/archive/2012/02/19/2358704.html alex: http://www.cnblogs.com/alex371 ...
- Solr 配置连接数据库
前面我们将solr安装并创建了core同时也配置可IK分词器,接下来我们通过配置连接Mysql数据库并把数据导入到solr(使用ik分词器). 1.配置managed-schema文件 Request ...