解决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) ...
随机推荐
- JZOJ 5344. 摘果子
Description Input Output Sample Input 7 9 39 6 13 2 22 6 7 4 -19 5 28 6 -17 1 2 1 3 2 4 1 5 4 6 2 7 ...
- 怎么选取训练神经网络时的Batch size?
怎么选取训练神经网络时的Batch size? - 知乎 https://www.zhihu.com/question/61607442 深度学习中的batch的大小对学习效果有何影响? - 知乎 h ...
- [译]The Python Tutorial#10. Brief Tour of the Standard Library
[译]The Python Tutorial#Brief Tour of the Standard Library 10.1 Operating System Interface os模块为与操作系统 ...
- Python中的正则
regex_lst = [ ('字符组',), ('非打印字符',), ('特殊字符',), ('定位符',), ('限定符',), ('re模块',), ('分组命名',), ('或匹配',), ( ...
- 2017 ACM-ICPC网络赛 H.Skiing 有向图最长路
H.Skiing In this winter holiday, Bob has a plan for skiing at the mountain resort. This ski resort h ...
- HDU:2846-Repository
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2846 Repository Time Limit: 2000/1000 MS (Java/Others) ...
- Codeforces Round #496 (Div. 3) ABCDE1
//B. Delete from the Left #include <iostream> #include <cstdio> #include <cstring> ...
- 6、python中的元组
元组(tuple)是python中有序.不可变的数据结构.元组还是python四种数据结构中唯一一种不可变的数据结构. 一.前言 元组在很多方面都变现得跟列表一样,除了列表储存得对象是可变得,而元组储 ...
- Spark性能优化:shuffle调优
调优概述 大多数Spark作业的性能主要就是消耗在了shuffle环节,因为该环节包含了大量的磁盘IO.序列化.网络数据传输等操作.因此,如果要让作业的性能更上一层楼,就有必要对shuffle过程进行 ...
- 自我介绍&友链
目录 此博客 我是谁? 友链 此博客 此博客主要更新一些题解什么的...(随缘啦) 本蒟蒻太菜了,博客中出现了错误希望指出,谢谢! . . 我是谁? SD的一名蒟蒻!emm... 喜欢摸鱼. 喜欢抽卡 ...