运行代码执行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()阻塞问题的更多相关文章

  1. JAVA创建子进程并处理waitFor() 阻塞问题

    虽然很想休息,但是想想还是要把今天学的东西记下来,不然以后再用还是新知识. 新建一个线程类读取子进程的汇报信息和错误信息,避免阻塞 class StreamGobbler extends Thread ...

  2. 解决session阻塞的问题

    简介 对于数据库运维人员来说创建session或者查询时产生问题是常规情况,下面介绍一种很有效且不借助第三方工具的方式来解决类似问题. 最近开始接触运维工作,所以自己总结一些方案便于不懂数据库的同事解 ...

  3. 解决一阻塞语句CPU直降15%

    原本只是部署作业获取数据库中阻塞语句,中午测试汇集阻塞数据,发现某一服务器写入386行,而其他服务器只写入几行.登录对应服务器查看详细信息,发现有四个时间点分别写入100来行记录对于第一行:会话183 ...

  4. 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密

    下面的图片是我使用firefox和chrome浏览百度首页时候记录的http请求 下面是firefox: 下面是chrome: 在浏览百度首页前我都将浏览器的缓存全部清理掉,让这个场景最接近第一次访问 ...

  5. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  6. “惊群”,看看nginx是怎么解决它的

    在说nginx前,先来看看什么是“惊群”?简单说来,多线程/多进程(linux下线程进程也没多大区别)等待同一个socket事件,当这个事件发生时,这些线程/进程被同时唤醒,就是惊群.可以想见,效率很 ...

  7. IO之同步、异步、阻塞、非阻塞 (2)

    [原创链接: http://www.smithfox.com/?e=191, 转载请保留此声明, 谢谢! ] I/O Model 是一个很大的话题, 也是一个实践性很强的事情, 网上有各种说法和资料, ...

  8. [Python]再学 socket 之非阻塞 Server

    再学 socket 之非阻塞 Server 本文是基于 python2.7 实现,运行于 Mac 系统下 本篇文章是上一篇初探 socket 的续集, 上一篇文章介绍了:如何建立起一个基本的 sock ...

  9. Js中for循环的阻塞机制

    Js阻塞机制,跟Js引擎的单线程处理方式有关,每个window一个JS线程.所谓单线程,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码. 由于浏览器是事件驱动的(Event driven) ...

随机推荐

  1. ZendFramework-2.4 源代码 - 关于配置

    $applicationConfig = $serviceManager->setService('ApplicationConfig'); // 获取配置 /data/www/www.doma ...

  2. python各种操作列表的方法及案例

    一.循环的使用方法 names = ["张真","刘德华","哈林","谢霆锋","张柏芝"] fo ...

  3. Liunx环境--Node部署记录

    1.看看环境里有没有装Node which node 2.找个目录安装 (1)/usr/local/node/download 执行下载 wget https://nodejs.org/dist/v8 ...

  4. IIC如何释放数据总线? 为什么=1就是释放?

    最近看IIC原理,释放一词经常用遇到,在nxp的标准中也有看到,有点疑惑,因此百度,在百度知道中,有大佬的解释,可以看看何为“释放”,结合数字电子技术,应该可以理解了. 下面总结了一下三个解释何为“释 ...

  5. stm32的systick原理与应用

    /* SysTick滴答定时器 一.功能 SysTick定时器是一个简单的定时器,CM3\CM4内核芯片都具备此定时器.SysTick定时器常用来做延时,采用实时系统时则用来做系统时钟.无论用作延时还 ...

  6. Go语言之反射(二)

    反射的值对象 反射不仅可以获取值的类型信息,还可以动态地获取或者设置变量的值.Go语言中使用reflect.Value获取和设置变量的值. 使用反射值对象包装任意值 Go语言中,使用reflect.V ...

  7. bash shell命令与监测的那点事(三)

    bash shell命令与监测的那点事之df与du 前两篇介绍了bash shell的进程监控指令,但是有时候你需要知道在某个设备上还有多少磁盘空间.首先介绍df命令: df命令 df命令就是用来轻松 ...

  8. STL 里面的几个容器简叙

    出处:http://blog.csdn.net/niushuai666/article/details/6654951 list1.list的成员函数push_back()把一个对象放到一个list的 ...

  9. Eclipse启动错误:A Java Runtime Environment(JRE) or Java Development Kit(JDK) must be available……

    确保Jdk,Jre都安装完成并且环境变量配置无误的情况下,自动Ecplise报错如下: A Java Runtime Environment (JRE) or Java Development Kit ...

  10. caffe工程配置问题

    一开始是碰到没有caffe/caffe.hpp文件的问题,不知道怎么弄.通过百度,知道了在makefile文件里加入头文件路径和库文件路径就行. 首先是caffe.pb.h丢失问题,解决方法:http ...