为什么父进程不处理标准输入输出子进程会挂起(Java)?

最近写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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值