java - 为什么 java.lang.process 的 readline() 在读取具有相同操作系统的不同机器上的输入流时表现不同

标签 java multithreading process operating-system readline

我在几个不同的 Linux 机器(4+)上测试了这段代码(如下),它工作得很好。然而,在一台 Linux 机器上,我遇到了 readline() 因错误 inputStream(errorStream) 而挂起的问题。该流应该是空的,因此我怀疑该框没有向错误流写入行终止符。我更改了代码以使用 read() 而不是 readline()...但 read() 也挂起。

我尝试首先检索输入 inputStream,这有效,并且错误输入流的 readline()/read() 没有挂起。我无法这样做,因为我需要首先获取可能的错误。看起来是一个死锁,我能够通过让每个输入流从它自己的线程读取来解决这个问题。为什么我只在一个盒子上看到这个问题?是否有特定于该盒子的内核设置或其他一些设置可能导致此问题?

   ProcessBuilder  processBuilder = new ProcessBuilder()
   try 
   {
       Process processA = null;
       synchronized (processBuilder)
       {
           processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
           processA = processBuilder.start();
       }

       inputStream = processA.getInputStream();
       reader = new BufferedReader(new InputStreamReader(inputStream));

       errorStream = processA.getErrorStream();
       errorReader = new BufferedReader(new InputStreamReader(errorStream));

       String driverError;

       while ((driverError = errorReader.readLine()) != null)
       {
           //some code
       }

最佳答案

Why did I only see this issue on one box?

很可能是因为正在运行的脚本中的某些内容......及其与其环境的交互(例如文件、环境变量等)

Is there a kernel setting or some other setting specific to this box that could have caused this?

有可能但不太可能是内核设置。可能是“别的东西”。事实上,这一定是 Java 应用程序之外的“某些东西”造成的,至少是部分原因。

<小时/>

我建议您暂时(至少)执行以下操作:

   ProcessBuilder  processBuilder = new ProcessBuilder();
   processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
   processBuilder.redirectErrorStream(true);

   processA = processBuilder.start();

   inputStream = processA.getInputStream();
   reader = new BufferedReader(new InputStreamReader(inputStream));
   String line;

   while ((line = reader.readLine()) != null) {
       System.out.println(line);
   }
   System.out.println("Return code is " + processA.exitValue());

这样您就可以看到所有输出是什么。

如果外部进程未能在最后一行末尾添加换行符,那么应该不会有问题。 Java 进程将在输入流上看到 EOF,并且 BufferedReader 将返回它所包含的字符...并在下一次调用时返回 null。

<小时/>

另一种可能性是外部进程正在阻塞,因为它正在尝试从其标准输入中读取数据。

<小时/>

更新

The redirectErrorStream also resolved the issue, but I need the error stream separate.

好吧,如果它确实(可靠地)解决了问题,那么(很可能)意味着您必须读取外部进程 stdoutstderr并行。简单的方法是创建 2 个线程来分别读取和缓冲两个流。例如:Capturing stdout when calling Runtime.exec

(您的问题是由于管道的缓冲容量有限。外部问题很可能是在将内容写入 stdoutstderr 之间交替。如果当其中一个管道“已满”时,尝试写入该管道,它将阻塞。但是,如果您的应用程序正在读取所有其他管道(到 EOF)之前它读取阻塞的管道,那么一切都会死锁。外部进程卡在 PIPE_W 状态的事实更能证明这一解释。

您在不同系统上看到不同行为的一个可能原因是管道中的缓冲量取决于系统。但这也可能是由于外部流程正在执行的操作存在差异所致;例如它的输入。)

关于java - 为什么 java.lang.process 的 readline() 在读取具有相同操作系统的不同机器上的输入流时表现不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18009363/

相关文章:

android - otto eventbus for android 在发布版本中表现不同

linux - gdb coredump - 调用函数或继续执行

windows - 使用CMD根据其描述查找Windows进程

java - 数组索引越界错误

java - 如何在 Java8 流/过滤器中使用非最终变量?

java - Java 中的 Kotlin 结果类型

c - 理论、流程 fork()

java - doGet 在 servlet 中不起作用

c++ - 当函数执行结束时, vector 中的线程会发生什么?

java - SWT/Swing -> 线程 hell