运行代码执行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会使用更少的空间,但如果已经知道是汉字 推荐GB2312private 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();}@Overridepublic 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+F6public 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及时的读取最后缓冲区满了就卡住了。

至于能够不让子进程向输入流写入数据,是不是可以解决这个问题,还有待考证。

转载于:https://www.cnblogs.com/qiangqiangqiang/p/9634653.html

解决waitfor()阻塞问题相关推荐

  1. 阻塞会话_使用根会话解决SQL阻塞链并进行故障排除

    阻塞会话 In this article, we will study how to recognize and resolve the SQL blocking chain by determini ...

  2. java Process.waitFor阻塞

    关于java Process waitFor() 进程阻塞问题 摘录自:http://lelglin.iteye.com/blog/1487351 问题:有同学遇到java调用Process.exec ...

  3. java process的waitfor()阻塞问题

    http://blog.csdn.net/jimzhai/article/details/7864806 Runtime runtime = Runtime.getRuntime(); Process ...

  4. Java Process.waitFor() 阻塞卡住不返回

    1. 现象 在Java程序中,启动另一个进程执行一个命令时可以使用ProcessBuilder类启动一个进程. 以运行 ps 命令为例: ProcessBuilder processBuilder = ...

  5. 高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)

    以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.并发式IO的解决方案 所谓并发式IO,即上节中提及的鼠标和键盘都已经启动. 1.非阻塞式IO 使用fcntl函 ...

  6. Process#waitFor()阻塞问题

         有时需要在程序中调用可执行程序或脚本命令: Process process = Runtime.getRuntime().exec(shPath); int exitCode = proce ...

  7. weblogic 解决线程阻塞

    最近,发现应用在weblogic服务器运行一段时间后,会报超时错误,查看weblogic后台日志: <Error> <WebLogicServer> <BEA-00033 ...

  8. 解决connect阻塞

    步骤1: 设置非阻塞,启动连接 实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的.这样调用 connect 可以立刻返回,根据返回值和 errno 处理三种情况: (1) 如果返回 ...

  9. JavaScript异步加载,解决js阻塞

    1.defer: 在script标签里添加defer,用于外部链接js文件,也可以异步加载内部脚本,会等待dom树生成后再执行js脚本代码 <script src="01.js&quo ...

最新文章

  1. 周刊#003提要:吴恩达团队盘点2019 AI 大事件圣诞 AI 论战
  2. 14 图的基础知识-几种常用的存储结构
  3. Oracle感慨(转)
  4. SAP-CO.创建成本中心,作业类型,内部订单
  5. python数据分析入门
  6. WPF中StringToImage和BoolToImage简单用法
  7. java final 修改_“无法改变的设计”——浅谈Java中的final关键字
  8. P1032-字串变换【bfs】
  9. mysql导数据出指定数量_mysql导出指定数据或部份数据的方法
  10. phpcmsV9怎样在单页中调用后台栏目SEO设置的Meta_title
  11. 售前工程师的成长---一个老员工的经验之谈(5)
  12. 怎么增加一个工位?ApiPost工位有什么用?
  13. 一张图带你看懂 ,web前端开发应该知道的HTML5六大趋势
  14. python 计算循环次数,05.Python循环
  15. Linux升级python版本
  16. DEAP2.1 使用方法(运筹学)
  17. SSH框架的详细介绍
  18. 手机如何远程连接服务器
  19. $java_home位置_关于java home:echo $ JAVA_HOME不返回jdk位置
  20. ipa文件如何下载安装OR如何设置IPA文件下载链接

热门文章

  1. 某互联网公司校园招聘的小组面试题
  2. 往ABAP gateway system上和Cloud Foundry上部署HTML5应用
  3. sap.ui.require in SAP UI5 and require in nodejs
  4. mysql数据库财务_MySQL数据库——从入门到删库跑路(二)
  5. matlab中rowset什么意思,没什么用的matlab代码1
  6. servlet的注解开发
  7. python购物车程序2019_Python——购物车程序(列表的应用)
  8. linux命令大写输入,Linux命令行:对内容进行大小写字符转换 ????
  9. php基础小结,PHP基础学习小结
  10. python pip全称_“ pip install”和“ pip install”之间有什么区别和“ python -m pip install”?...