为什么父进程不处理标准输入输出子进程会挂起(Java)?
来源:互联网 发布:创建视图的sql语句代码 编辑:程序博客网 时间:2024/05/01 18:09
最近写Java的多进程程序时遇到一个奇怪的问题,发现程序运行一段时间以后会自动挂起。按道理来说子进程和父进程之间是没有太大的关系的,父进程只是用于开启一个新的子进程,之后就没怎么联系了。最后查到了stackoverflow上面的一片帖子,写的不错。http://stackoverflow.com/questions/16983372/why-does-process-hang-if-the-parent-does-not-consume-stdout-stderr-in-java
Java doesn’t do anything in this area. It just uses OS services to create the pipes.
All Unix like OSs and Windows behave the same in this regard: A pipe with a 4K is created between parent and child. When that pipe is full (because one side isn’t reading), the writing process blocks.
This is the standard since the inception of pipes. There is not much Java can do.
What you can argue is that the process API in Java is clumsy and doesn’t have good defaults like simply connecting child streams to the same stdin/stdout as the parent unless the developer overrides them with something specific.
I think there are two reasons for the current API. First of all, the Java developers (i.e. the guys at Sun/Oracle) know exactly how the process API works and what you need to do. They know so much that it didn’t occur to them that the API could be confusing.
The second reason is that there is no good default that will work for the majority. You can’t really connect stdin of the parent and the child; if you type something on the console, to which process should the input go?
Similarly, if you connect stdout, the output will go somewhere. If you have a web app, there might be no console or the output might go somewhere where no one will expect it.
You can’t even throw an exception when the pipe is full since that can happen during the normal operation as well.
总结一下就是这个问题可能跟Java关系不大,应该是操作系统对pipe处理的问题。因为父子进程之间通信可以利用匿名管道,但是如果子进程往管道里面的数据“塞”满了,父进程却“迟迟”不取,那么操作系统就会hang子进程,不让它接着写数据了。所以这时候子进程就会没反应了。挂起了嘛。
原因找到了,解决这个问题就很简单了,直接开启一个线程不停地去读取匿名管道里面的数据即可。
String javaHome = System.getProperty("java.home");String javaBin = javaHome + File.separator + "bin" + File.separator + "java";String classpath = System.getProperty("java.class.path");String className = klass.getCanonicalName();ProcessBuilder builder = new ProcessBuilder(javaBin, "-cp", classpath, className, String.valueOf(mode));builder.redirectErrorStream(true);process = builder.start();// process.waitFor();InputStream myIS = process.getInputStream();new Thread(){ public void run() { if(process == null) return ; InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; try { while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Game closed!"); } }.start();
- 为什么父进程不处理标准输入输出子进程会挂起(Java)?
- 一个进程为什么会默认打开三个标准输入输出
- system会挂起父进程
- 重定向子进程标准输入输出
- Linux 后台执行 java 进程不挂起
- 父进程为什么要创建子进程
- fork_子进程会复制父进程的缓存空间
- 缓冲区问题:子进程会复制父进程的缓冲区
- fork一个子进程会拷贝父进程的什么
- java中父进程与子进程
- exit会结束当前进程。但是会结束父进程和子进程吗?
- 父进程 子进程
- 父进程子进程
- 子进程继承父进程的什么不继承什么
- 子进程在复制父进程的信号处理方式
- 子进程在复制父进程的信号处理方式
- C++实现的两个进程,父进程处理SIGUSR2,子进程处理SIGUSR1
- 为什么会引入线程(进程,优缺点,模型)!!!
- JSP中文乱码问题终极解决方案
- 关于cocos2d-x3.0和2.0之间的区别
- std::string::npos
- 开发注释方法说明
- struts.xml 中配置常量constant详解
- 为什么父进程不处理标准输入输出子进程会挂起(Java)?
- 用c语言判断计算机是大端模式还是小端模式
- PCIe数据峰值带宽和有效带宽计算
- 实现 boost lexical_cast(基本类型转换)
- Linear Regression_Note of Machine Learning_Andrew NG
- 进制转换
- LayoutParams的用法,及LayoutInflater区别
- c++技术系统学习资料
- javascript的一些小知识1