问题:

在Java程序中,通过Runtime.getRuntime().exec()执行一个Linux脚本导致程序被挂住,而在终端上直接执行这个脚本则没有任何问题。
原因:
先来看Java代码:

    public final static void process1(String[] cmdarray) {Process p = null;BufferedReader br = null;try {p = Runtime.getRuntime().exec(cmdarray);br = new BufferedReader(new InputStreamReader(p.getInputStream()));String line = null;while ((line = br.readLine()) != null) {System.out.println(line);}p.waitFor();} catch (Exception e) {e.printStackTrace();} finally {if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}if (p != null) {p.destroy();}}}

脚本内容很简单,主要内容是将一个指定的tar.gz文件解压到指定目录中。
程序被挂住后,查看进程列表,发现了几个可疑点:

neil@-bash:~/work/tgz$ps ux | grep dowjones
neil  2079   0.0  0.0  2435492    264 s001  R+   10:56上午   0:00.00 egrep dowjones
neil  2077   0.0  0.0  2435080    652   ??  S    10:56上午   0:00.24 tar xvf dowjones.tar.gz
neil  2073   0.0  0.0  2435488    792   ??  S    10:56上午   0:00.00 /bin/bash /Users/neil/bin/genova/genova_crm.sh /Users/neil/work/tgz/dowjones.tar.gz /Users/neil/work/dest/dowj

其中genova_crm.sh 就是要执行的脚本,tar xvf dowjones.tar.gz 就是执行解压的命令。
可以看到,程序卡在tar命令上,这个命令被挂住了,非常奇怪的事情。。。
再次查看JDK文档,发现Process的文档上说标准缓冲区大小有限,不正确操作输入输出流时可能导致程序挂住。
单独执行tar xvf dowjones.tar.gz命令时,发现有N多输出,而通过Java执行时,没有看到那些输出。
Java程序中只获取了标准输出流,没有获取错误输出流,那么有可能是错误输出缓冲区满而导致tar命令挂住。

解决方法:
修改Java程序,标准输出流与错误输出流均要处理,保证输出缓冲区不会被堵住。具体作法是用一个异步线程读取标准输出,读完即扔,让主线程读取错误输出流:

    public final static void process1(String[] cmdarray) {try {final Process p = Runtime.getRuntime().exec(cmdarray);new Thread(new Runnable() {@Overridepublicvoid run() {BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));try {while (br.readLine() != null);br.close();} catch (IOException e) {e.printStackTrace();}}}).start();BufferedReader br = null;br = new BufferedReader(new InputStreamReader(p.getErrorStream()));String line = null;while ((line = br.readLine()) != null) {System.out.println(line);}p.waitFor();br.close();p.destroy();} catch (Exception e) {e.printStackTrace();}}

重新执行,发现程序可以正常执行了,tar命令的回显被打印出来了。问题解决。
这可能跟特定的tar包有关,执行tar解压时,明显可以看到回显字符串中有些乱码,回显全部被输出到错误流了。

上述方法可以避免标准输出或错误输出缓冲区满从而挂住主程序的问题,但是需要同时处理两个流,有重复之嫌。如果能把标准输出和错误输出并为一个流,那只需要处理一个流即可。ProcessBuilder提供了这种能力。

创建Process有两种方式,一种就是上述的通Runtime.exec来得到,还有一种可以通ProcessBuilder.start()来产生一个Process实例。
ProcessBuilder可以先设置必要的参数数据,如命令、环境变量、工作目录、重定向错误流到标准输出,然后start()根据这些参数来生成一个Process实例,启动一个子进程来执行相应的命令。
代码如下:

    public final static void process(String[] cmdarray) throws Throwable {ProcessBuilder pb = new ProcessBuilder(cmdarray);pb.redirectErrorStream(true);Process p = null;BufferedReader br = null;try {p = pb.start();br = new BufferedReader(new InputStreamReader(p.getInputStream()));String line = null;logger.info("Invoke shell: {}", StringUtils.join(cmdarray, " "));while ((line = br.readLine()) != null) {logger.info(line);}p.waitFor();} finally {if (br != null) {br.close();}if (p != null) {p.destroy();}}}

通过上述代码可以看到,错误流被重定向到标准输出流,那么程序只需要处理标准输出就可以了。

调用Runtime.getRuntime().exec()执行Linux脚本导致程序挂住的问题分析相关推荐

  1. Runtime.getRuntime.exec()执行linux脚本导致程序卡死问题

    问题: 在Java程序中,通过Runtime.getRuntime().exec()执行一个Linux脚本导致程序被挂住,而在终端上直接执行这个脚本则没有任何问题. 原因: 先来看Java代码: pu ...

  2. runtime无法执行grep_Runtime.getRuntime.exec()执行linux脚本导致程序卡死有关问题

    Runtime.getRuntime.exec()执行linux脚本导致程序卡死问题 问题: 在Java程序中,通过Runtime.getRuntime().exec()执行一个Linux脚本导致程序 ...

  3. 如何在JAVA代码中执行 exec master..xp_cmdshell @cmd // 当作SQL语句调用就成了 或者调用 Runtime.getRuntime().exec

    例如: //package FS; import java.io.IOException; import java.sql.*; public class BCP {  static Connecti ...

  4. Runtime.exec()执行linux shell

    最好的执行系统命令的方法就是写个bat文件或是shell脚本.然后调用,那样修改和实现就简点多了. 现在执行外部命令,主要的方式,还是通过调用所以平台的SHELL去完成,WINDOWS下面就用CMD, ...

  5. java runtime.exec 阻塞_关于Runtime.getRuntime().exec()产生阻塞的2个陷阱

    背景 相信做java服务端开发的童鞋,经常会遇到Java应用调用外部命令启动一些新进程来执行一些操作的场景,这时候就会使用到Runtime.getRuntime().exec(),然而这个方法如果不谨 ...

  6. Runtime.getRuntime.exec的陷阱

    近期在项目有一个需求,需要通过Java的Runtime.getRuntime().exec()执行外部的一个批处理脚本,发现在执行的时候,出现各种诡异的问题,脚本执行一半出现卡死.而脚本在终端上运行没 ...

  7. java执行python脚本_使用Runtime.getRuntime().exec()在java中调用python脚本

    举例有一个Python脚本叫test.py,现在想要在Java里调用这个脚本.假定这个test.py里面使用了拓展的包,使得pythoninterpreter之类内嵌的编译器无法使用,那么只能采用ja ...

  8. Runtime.getRuntime().exec()操作脚本

    项目场景: 在项目中我们需要调用linux语句给企业微信发邮件 问题描述 在服务器上调用命令却能发送成功,但是使用Runtime.getRuntime().exec()却一直发送不成功 @Overri ...

  9. Runtime.getRuntime().exec()调用外部程序

    场景:linux下,在web工程里调用一个C++程序,实现代码如下: StringBuffer cmd = new StringBuffer(); cmd.append("nohup &qu ...

最新文章

  1. VUE保存页面的数据,VUE页面显示就执行某个函数,VUE页面隐藏就执行某个函数
  2. 成功解决ModuleNotFoundError: No module named ‘sklearn.grid_search‘
  3. 帝豪gs车机系统wince_有了帝豪GS,生活变得越来越好,很不错
  4. 科大星云诗社动态20210329
  5. 2021年宝鸡中学高考成绩查询,宝鸡各高中2020年高考喜报成绩一览
  6. 日期相减计算年_函数 | Excel有个“秘密”函数,计算年龄工龄特方便
  7. CodeSmith 基础用法和例子
  8. html中给div设置的属性怎么样才能拿得到_HTML与CSS结合的三种方式:优先级比较...
  9. elasticsearch集群选举源码解析
  10. 【深入浅出etcd系列】3. 日志同步
  11. Confluence 6 用户目录图例 - 使用 LDAP 授权,在用户第一次登陆时拷贝用户
  12. PRML笔记 第一章 Introduction
  13. 72000 Star 下载工具被 GitHub 下架,背后的数字千年版权法案是什么?
  14. mysql创建备份文件,MySQL定时备份操作
  15. 软件读写中文字符的文件出现乱码的解决办法
  16. SpringBoot使用模板动态导出PDF使用itextpdf
  17. 【笔试or面试】美团2014校园招聘
  18. Web前端大作业—— 饮食餐饮网站 咖啡网站pc端带轮播(5个页面)HTML+CSS+JavaScript 学生美食网页设计作品 学生餐饮文化网页模板
  19. 现在才知道,菊花茶可不能随便喝!
  20. python画板——小猪佩奇

热门文章

  1. 【历史上的今天】9 月 27 日:“3Q 大战”正式打响;第一个被通缉的电脑黑客;知名“美女病毒”作者被定罪
  2. aardio 安装 Python 模块,快速开发界面,生成独立 EXE 一把梭
  3. jupyter notebook是一种Web 应用,能让用户将说明文本、数学方程、代码和可视化内容全部组合到一个易于共享的文档中
  4. 计算机操作系统——银行家算法
  5. 决策树CART、ID3、C4.5原理梳理
  6. Vue Mixin 与小程序 Mixins 应用
  7. 【信奥赛一本通】1183:病人排队(详细代码)
  8. 10个流行常用的Django第三方包-大江狗推荐
  9. 大话nbu二(netbackup的基本配置)
  10. 打印表格留标题怎么设置_打印Excel表格时每页都打印标题行的设置方法