Java 为什么使用重定向的输入/输出流执行交互进程会导致应用程序停止?

Java 为什么使用重定向的输入/输出流执行交互进程会导致应用程序停止?,java,linux,console,io,stream,Java,Linux,Console,Io,Stream,我有一个控制台Java程序,它在一个单独的进程中执行sh-I,并在进程的输入/输出流和相应的系统流之间复制数据: import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; class StreamCopier implements Runnable { private InputStream in; private OutputStream out; pub

我有一个控制台Java程序,它在一个单独的进程中执行
sh-I
,并在进程的输入/输出流和相应的系统流之间复制数据:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class StreamCopier implements Runnable {
    private InputStream in;
    private OutputStream out;

    public StreamCopier(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n = 0;
            byte[] buffer = new byte[4096];
            while (-1 != (n = in.read(buffer))) {
                out.write(buffer, 0, n);
                out.flush();
            }
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

public class Test {
    public static void main(String[] args)
            throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec("sh -i");
        new Thread(new StreamCopier(
                process.getInputStream(), System.out)).start();
        new Thread(new StreamCopier(
                process.getErrorStream(), System.err)).start();
        new Thread(new StreamCopier(
                System.in, process.getOutputStream())).start();
        process.waitFor();
    }
}
在Linux下运行它会产生以下结果:

$ 
[1]+  Stopped                 java -cp . Test
有人能澄清为什么应用程序被停止,以及如何避免吗


这与我的有关,但我认为这一特定问题值得单独关注。

你正被SIGTTIN或Sigttoo阻止。当这些信号试图对TTY执行IO时,它们被发送到后台进程。在这种情况下,“背景”是指“不是终端的控制过程组”。我怀疑你正在开发的子shell正在创建一个新的pgrp并接管你的tty。然后父程序(java)执行IO(在您的例子中可能是从TTY读取)并获取SIGTTIN


确认这一理论的一个简单方法是用更简单的东西(不是shell)替换sh,它不会试图接管tty。

您可以通过调用shell(如
sh-i+m
)来关闭作业控制,这将阻止它接管tty。这意味着
fg
bg
命令将不起作用,Ctrl+Z将挂起Java应用程序、shell和所有从其启动的程序

如果您仍然需要作业控制,那么应该使用伪终端与shell通信,这将为shell创建一个新的tty供其使用,但我认为Java不支持这一点