Java程序员的日常 —— 多进程开发IO阻塞问题
本篇仍旧是源于最近的工作,总结一下纪念那些年埋下的坑...
背景故事
需求:“使用进程方式启动另一个程序!”
开发:“OK! Runtime.getRuntime().exec("xxxx")”
需求:“启动以后能看到输出消息不!”
开发:“OK!”
Process process = null;
try {
process = Runtime.getRuntime().exec("ipconfig /all");
} catch (IOException e) {
e.printStackTrace();
}
try {
String line;
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"GBK"));
while(null != (line = br.readLine())){
System.out.println(line);
}
System.out.println("---------------------------------------------------------------------------------------");
InputStream is_error = process.getErrorStream();
BufferedReader br_error = new BufferedReader(new InputStreamReader(is_error,"GBK"));
while(null != (line = br_error.readLine())){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
于是,神坑挖好了!
遇到的问题
由于运行的程序比较复杂,有可能出现错误输出。这时就不好保证是错误输出还是标准输出哪个先到。但是上面的程序中,使用了同步的方式输出子进程的消息,结果就导致了子进程阻塞。
解决方案1:使用缓冲区缓存消息
解决方案2:使用ProcessBuilder合并标准输出和错误
仍然源自于上面的博客:
try{
String[] cmds = {"ipconfig","/all"};
ProcessBuilder builder = new ProcessBuilder(cmds);
//合并输出流和错误流
builder.redirectErrorStream(true);
//启动进程
Process process = builder.start();
//获得输出流
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(),"GBK"));
String line = null;
while (null != (line = br.readLine())){
System.out.println(line);
}
}catch(IOException e){
e.printStackTrace();
}
上面的代码中builder.redirectErrorStream(true);
就可以帮助你把错误合并到标准输出里面。
于是,很好奇这个ProcessBuilder到底什么东东。
阅读API —— 什么是ProcessBuilder
ProcessBuilder用于创建操作系统进程,每个ProcessBuilder实例都管理一个进程属性集合。通过调用start()方法,可以通过这些属性创建出一个进程。start()方法可以被多次调用,来创建多个独立的进程。
每个builder管理着下面的进程属性:
cmmand
命令,比如{“ipcofig”,"/all"}
environment
环境变量,子进程会直接使用当前进程的环境变量。环境变量是独立的,因此可以被修改,但是不会影响其他的进程。
directory
工作目录,如果返回的是Null,说明当前目录使用的是系统变量user.dir所在的目录。
redirectErrorStream属性
默认是false。Flase意味着标准输出和标准错误是两个独立的流,可以通过Process.getInputStream()和Process.getErrorStream()方法获得。
如果这个值设置为true,那么标准错误将会合并到标准输出中,并且发往同一个目标地址(这种特性使得错误消息可以很方便的和输出消息一起管理),此时,如果你再想要单独获取错误输出流,就会得到null。
线程安全
注意这个类不是线程安全的,因此如果多个线程使用ProcessBuilder实例,并且修改属性,那么可能会造成冲突。因此需要在外面进行线程同步。
启动
可以简单的向下面这样启动一个进程:
Process p = new ProcessBuilder("myCommand", "myArg").start();
样例
下面是官方文档中给出的样例,样例中修改了工作目录以及环境变量,并且把标准错误和标准输出合并输出到日志文件中:
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
File log = new File("log");
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.appendTo(log));
Process p = pb.start();
assert pb.redirectInput() == Redirect.PIPE;
assert pb.redirectOutput().file() == log;
assert p.getInputStream().read() == -1;
Java程序员的日常 —— 多进程开发IO阻塞问题的更多相关文章
- Java程序员的日常 —— 多进程开发
最近再弄进程管理相关的工作,因此必要的就涉及到各种系统下关于进程的管理. 这里简单的介绍下: 如何在Java中执行命令 在windows下肯定是dos命令了,而在linux则为shell命令.执行的方 ...
- Java程序员的日常——经验贴(纯干货)
工作当中遇到的事情比较杂,因此涉及的知识点也很多.这里暂且记录一下,今天遇到的知识点,纯干货~ 关于文件的解压和压缩 如果你的系统不支持tar -z命令 如果是古老的Unix系统,可能并不认识tar ...
- 2018年,Java程序员转型大数据开发,是不是一个好选择?
近日网上有一篇关于Java程序员职场生存现状的文章“2017年 Java 程序员,风光背后的危机”,在Java程序员圈子里引起了广泛关注和热议. 2017年,Java 程序员面临更加激烈的竞争. 不得 ...
- Java程序员的日常—— Properties文件的读写
在日常的Java程序开发中,Properties文件的读写是很常用的.经常有开发系统通过properties文件来当做配置文件,方便用户对系统参数进行调整. 那么本片就来简单的介绍下,如何使用Prop ...
- Java程序员的日常—— 《编程思想》关于类的使用常识
Java虽然利用JVM,让程序员可以放心大胆的使用,可是仍然会出现内存泄露等问题.世上没有绝对的银弹,因此也不能完全把所有的任务都交给JVM,了解Java中的初始化与垃圾回收还是必不可少的知识. 关于 ...
- Java程序员的日常—— 垃圾回收中引用类型的作用
在Java里面,是不需要太过于关乎垃圾回收,但是这并不意味着开发者可以不了解垃圾回收的机制,况且在java中内存泄露也是家常便饭的事情.因此了解垃圾回收的相关知识就显得很重要了. 引用,在垃圾回收中是 ...
- Java程序员的日常—— Arrays工具类的使用
这个类在日常的开发中,还是非常常用的.今天就总结一下Arrays工具类的常用方法.最常用的就是asList,sort,toStream,equals,copyOf了.另外可以深入学习下Arrays的排 ...
- Java程序员的日常——经验贴(纯干货)二
继昨天的经验贴,今天的工作又收获不少. windows下编辑器会给文件添加BOM 在windows的编辑器中,为了区分编码,通常会添加一个BOM标记.比如,记事本.nodepade++.sublime ...
- Java程序员的日常——SpringMVC+Mybatis开发流程、推荐系统
今天大部分时间都在写业务代码,然后算是从无到有的配置了下spring与mybatis的集成. SpringMVC+Mybatis Web开发流程 配置数据源 在applicationContext.x ...
随机推荐
- c# 搭建高效分布式web (进一步实现软件的热插拔)
一 加入 和其他网站相同的特性 nginx 做代理 并且和IIS 进行搭配搭建 web 前台 二 缓存使用 memcached 和session 共享做服务器的缓存处理减轻sql数据库的压力 包含关系 ...
- 一个日期的下一个星期五 next_date
select next_day('18-5月-2001','星期五') nxt_day from dual;
- Android adb命令 一
adb的全称为Android Debug Bridge,就是起到调试桥的作用.通过adb我们可以在Eclipse中方面通过DDMS来调试Android程序,说白了就是debug工具.adb的工作方式比 ...
- [转]JUnit-4.11使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误
原文引自: http://blog.csdn.net/castle07/article/details/8553704 今天尝试使用JUnit,下载了最新的JUnit版本,是4.11,结果尝试使用发现 ...
- ContentProvider要点复习
ContentProvider要点复习 ContentProvider作为四大组件之一,发挥着举足轻重的作用.与之相关联的另外两个类分别是ContentResolver和ContentObserver ...
- Windows Phone 8.1 新特性 - 页面导航
本篇介绍一下Windows Phone 8.1 中页面导航的实现方式. 大家对Windows Phone 8 中页面导航的实现一定不陌生,我们使用 NavigationService 来实现.具体写法 ...
- MongoDB学习笔记-04 索引
索引是用来加速查询的.有了索引之后,数据库不必进行全表扫描,只需先在索引中查找,再根据找到的索引查找数据.MongoDB的索引几乎和传统关系型数据库一样. 创建索引 创建索引是在相应的集合中使用ens ...
- ios申请真机调试( xcode 5)详细解析
已经有开发证书的直接跳过第一步 第一步:申请"开发证书" 进入苹果开发者99美元账号: 选择:Certificates, Identifiers & Profiles 关于 ...
- 网上搜集了点资料,学web的人互相分享共同进步吧(php编码的好习惯必须养成)
网上搜集了点资料,学web的人互相分享共同进步吧 一.优秀的代码应该是什么样的? 优秀的PHP代码应该是结构化的.大段的代码应该被分割整理成一个个函数或方法,而那些不起眼的小段代码则应该加上注释,以便 ...
- Python-变量
1.Python的变量是什么 变量是用来存储计算机程序中的信息,唯一的目的是将数据存储在内存中. 2.Python变量的组成 变量由字母.数字.下划线组成: 变量的第一位不能是数字,可以是字母或下划线 ...