Java - 多个并发runtime.exec() InputStreams 的问题

发布于 2024-10-12 19:00:56 字数 4628 浏览 4 评论 0原文

我别无选择,只能通过对 VBScript 的多次 Runtime.exec() 调用来检索一些外部数据。我真的很讨厌这种实现,因为我失去了跨平台灵活性,但我最终可能会开发类似的 *nix 脚本来至少缓解问题。在有人问之前,我无法解决调用外部脚本来收集数据的需要。我将忍受由此带来的问题。

exec() 进程在扩展 Runnable 的自定义类中运行。它使用 BufferedReadergetInputStream() 读取数据。

编辑:根据要求添加了更多代码,但我不明白额外的代码是如何相关的:)我希望它有帮助,因为格式化需要一段时间!哦,如果我的代码风格很丑陋,请轻松一点,但鼓励建设性的批评...

public class X extends JFrame implements Runnable {

   ...
   static final int THREADS_MAX = 4;
   ExecutorService  exec;
   ...
   public static void main(String[] args) {
      ...
      SwingUtilities.invokeLater(new X("X"));
   } // End main(String[])

   public X (String title) {
      ...
      exec = Executors.newFixedThreadPool(THREADS_MAX);
      ...

      // Create all needed instances of Y
      for (int i = 0; i < objects.length; i++) {
         Y[i] = new Y(i);
      } // End for(i)

      // Initialization moved here for easy single-thread testing
      // Undesired, of course
      for (int i = 0; i < objects.length; i++) {
         Y[i].initialize(parent);
      } // End for(i)

   } // End X

   class Y implements Runnable {
      // Define variables/arrays used to capture data here
      String computerName = "";
      ...

      public Y(int rowIndex) {
         row          = rowIndex;
         ...
         computerName = (String)JTable.getValueAt(row, 0);
         ...
         exec.execute(this);
      } // End Y(int)

      public void run() {
         // Initialize variables/arrays used to capture data here
         ...

         // Initialization should be done here for proper threading
         //initialize(parent);
      } // End run()

      public void initialize(Z obj) {
         runTime = Runtime.getRuntime();
         ...

         try {
            process = runTime.exec("cscript.exe query.vbs " + computerName);
            stdErr  = process.getErrorStream();
            stdIn   = process.getInputStream();
            isrErr  = new InputStreamReader(stdErr);
            isrIn   = new InputStreamReader(stdIn);
            brErr   = new BufferedReader(isrErr);
            brIn    = new BufferedReader(isrIn);

            while ((line = brIn.readLine()) != null) {
               // Capture, parse, and store data here
               ...
            } // End while

         } catch (IOException e) {
            System.out.println("Unable to run script");
         } catch (Exception e) {
            e.printStackTrace();
         } finally {
            try {
               stdErr.close();
               stdIn. close();
               isrErr.close();
               isrIn. close();
               brErr. close();
               brIn.  close();
            } catch (IOException e) {
               System.out.println("Unable to close streams.");
            } // End try
         } // End try
      } // End initialize(Z)
      ...
   } // End class Y
} // End class X

如果我单独执行命令,我会按预期收集数据。但是,如果我在类的 run() 块中执行命令(这意味着调用是并发的,正如我所希望的那样),看起来好像只生成了一个输入流,其中所有BufferedReaders 并发消费。

为了调试该问题,我在控制台上输出每个消耗的行,并以正在读取输入流的类实例为前缀。我期望类似以下的内容,了解它们可能从实例到实例都是无序的,但单个实例的行顺序将完好无损:

exec 0: Line1
exec 1: Line1
exec 2: Line1
exec 0: Line2
exec 1: Line2
exec 2: Line2
exec 0: Line3
exec 1: Line3
exec 2: Line3
...

奇怪的是我得到了第一行的预期实例数输出(Microsoft (R) Windows Script Host Version 5.7),但在这一行之后,只有一个进程继续在输入流中生成数据,并且所有读取器随机使用这一流,例如这个例子:

exec 2: Microsoft (R) Windows Script Host Version 5.7
exec 0: Microsoft (R) Windows Script Host Version 5.7
exec 1: Microsoft (R) Windows Script Host Version 5.7
exec 0: line2
exec 1: line3
exec 2: line4
...

更糟糕的是,读取器停滞并且 readLine() 永远不会返回 null。我读到这种类型的行为可能与缓冲区大小有关,但是当我仅运行两个并发线程时,即使输出很短,它仍然表现出相同的行为。 stdErr 中没有捕获任何表明存在问题的内容。

为了查看这是否是脚本主机的限制,我创建了一个批处理文件,该文件同时START多个脚本实例。 我应该声明这是在 Java 之外的 cmd shell 中运行的,并启动了几个自己的 shell。但是,每个并发实例都完全返回了预期结果并且表现良好。

编辑:作为另一个故障排除想法,我决定重新启用并发,但通过将以下内容插入到我的 Y.run() 块中来错开我的初始化方法:

try {
   Thread.sleep((int)(Math.random() * 1200));
} catch (InterruptedException e) {
   System.out.println("Can't sleep!");
} // End try
initialize(monitor);

到我的代码中。我开始看到前几行有多个输出,但它很快就会恢复为使用同一生产者的多个消费者,并且一旦第一个完成的流关闭,其余的消费者就会引发异常。下一个消费者触发 IOException: Read error,其余的则触发 IOException: Stream closeed

根据 maaartinus 的说法,运行多个并发的 InputStreams 是可能的,所以现在的问题是是什么导致了不良行为?我如何独立抓取他们的输入流?如果可以避免的话,我不想只是为了处理回数据而写入临时文件。

I have no choice but to retrieve some external data by means of several Runtime.exec() calls to a VBScript. I truly hate this implementation, as I lose my cross-platform flexibility, but I may eventually develop similar *nix scripts to at least mitigate the problem. Before anyone asks, I cannot work around the need to call an external script to gather my data. I will live with the problems that causes.

The exec() processes are run in a custom class that extends Runnable. It uses a BufferedReader to read in the data from getInputStream().

Edit: more code added as requested, but I don't see how the extra code is relevant :) I hope it helps, because it took a while to format! Oh, and go easy on my code style if it's ugly, but constructive criticism is encouraged...

public class X extends JFrame implements Runnable {

   ...
   static final int THREADS_MAX = 4;
   ExecutorService  exec;
   ...
   public static void main(String[] args) {
      ...
      SwingUtilities.invokeLater(new X("X"));
   } // End main(String[])

   public X (String title) {
      ...
      exec = Executors.newFixedThreadPool(THREADS_MAX);
      ...

      // Create all needed instances of Y
      for (int i = 0; i < objects.length; i++) {
         Y[i] = new Y(i);
      } // End for(i)

      // Initialization moved here for easy single-thread testing
      // Undesired, of course
      for (int i = 0; i < objects.length; i++) {
         Y[i].initialize(parent);
      } // End for(i)

   } // End X

   class Y implements Runnable {
      // Define variables/arrays used to capture data here
      String computerName = "";
      ...

      public Y(int rowIndex) {
         row          = rowIndex;
         ...
         computerName = (String)JTable.getValueAt(row, 0);
         ...
         exec.execute(this);
      } // End Y(int)

      public void run() {
         // Initialize variables/arrays used to capture data here
         ...

         // Initialization should be done here for proper threading
         //initialize(parent);
      } // End run()

      public void initialize(Z obj) {
         runTime = Runtime.getRuntime();
         ...

         try {
            process = runTime.exec("cscript.exe query.vbs " + computerName);
            stdErr  = process.getErrorStream();
            stdIn   = process.getInputStream();
            isrErr  = new InputStreamReader(stdErr);
            isrIn   = new InputStreamReader(stdIn);
            brErr   = new BufferedReader(isrErr);
            brIn    = new BufferedReader(isrIn);

            while ((line = brIn.readLine()) != null) {
               // Capture, parse, and store data here
               ...
            } // End while

         } catch (IOException e) {
            System.out.println("Unable to run script");
         } catch (Exception e) {
            e.printStackTrace();
         } finally {
            try {
               stdErr.close();
               stdIn. close();
               isrErr.close();
               isrIn. close();
               brErr. close();
               brIn.  close();
            } catch (IOException e) {
               System.out.println("Unable to close streams.");
            } // End try
         } // End try
      } // End initialize(Z)
      ...
   } // End class Y
} // End class X

If I execute the commands individually, I gather the data as I expect. However, if I execute the commands in the run() block of the class (meaning the calls are concurrent, as I am hoping for), it appears as if only one input stream is generated, which all BufferedReaders consume concurrently.

To debug the issue, I output each consumed line on the console prefixed by which instance of my class was reading the input stream. I expect something like the following, understanding that they may be out of order from instance-to-instance, but the line order of a single instance would be intact:

exec 0: Line1
exec 1: Line1
exec 2: Line1
exec 0: Line2
exec 1: Line2
exec 2: Line2
exec 0: Line3
exec 1: Line3
exec 2: Line3
...

What's strange is I get the expected number of instances of the very first line of the output (Microsoft (R) Windows Script Host Version 5.7), but after this line, only one process continues to produce data in the input stream, and all readers randomly-consume this one stream, such as this example:

exec 2: Microsoft (R) Windows Script Host Version 5.7
exec 0: Microsoft (R) Windows Script Host Version 5.7
exec 1: Microsoft (R) Windows Script Host Version 5.7
exec 0: line2
exec 1: line3
exec 2: line4
...

To make matters worse, the readers stall and readLine() never returns null. I read that this type of behavior might have something to do with the buffer size, but when I run only two concurrent threads, even with a short output, it still exhibits the same behavior. Nothing is captured in stdErr to indicate there is a problem.

To see if this was a limitation of the script host, I created a batch file that STARTs multiple instances of the script concurrently. I should state this was run outside of Java, in a cmd shell, and launches several of its own shells. However, each concurrent instance fully returned the expected results and behaved well.

Edit: As another troubleshooting idea, I decided to re-enable concurrency, but stagger my initialization method by inserting the following into my Y.run() block:

try {
   Thread.sleep((int)(Math.random() * 1200));
} catch (InterruptedException e) {
   System.out.println("Can't sleep!");
} // End try
initialize(monitor);

into my code. I begin to see multiple outputs for the first few lines, but it quickly reverts to multiple consumers consuming the same producer, and as soon as the first completed stream closes, the rest of the consumers fire exceptions. The next consumer fires an IOException: Read error, and the rest fire IOException: Stream closed!

According to maaartinus, it IS possible to run multiple, concurrent InputStreams, so now the question becomes what is causing the undesired behavior? How can I independently grab their input streams? I don't want to have to write to a temporary file just to process the data back in, if I can avoid it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

救星 2024-10-19 19:00:56

我认为你需要小心 IO 变量的范围。这是一个运行良好的快速代码,具有来自 4 个子进程的并发输入流...

import java.io.*;

public class MultiExec {

        private final static String[] comLines = {
                        "date",
                        "ls /var/spool/postfix",
                        "ls -F /usr/local/bin",
                        "wc -l /etc/apache2/apache2.conf"};

        public void execute() {
                for (int i = 0 ; i < comLines.length ; i++) {
                        ExecutableChild ec = new ExecutableChild (i, comLines[i]);
                        new Thread (ec).start();
        }}

        public class ExecutableChild implements Runnable {

                private int prIndex;
                private String executable;

                public ExecutableChild (int k, String cmd) {
                        prIndex = k;
                        executable = cmd;
                }

                public void run () {
                        try {
                                Process child = Runtime.getRuntime().exec(executable);
                                BufferedReader br = new BufferedReader (new InputStreamReader (
                                                                child.getInputStream()));
                                for (String s = br.readLine() ; s != null ; s = br.readLine())
                                        System.out.println ("[" + prIndex + "] " + s);
                                br.close();
                        } catch (IOException ioex) {
                                System.err.println ("IOException for process #"+
                                                prIndex+ ": " + ioex.getMessage());
        }}}

        public static void main (String[] args) {
                new MultiExec().execute();
        }
}

上述代码的输出 (% javac MultiExec.java; java MultiExec)

[2] tomcat*
[0] Thu Jan 20 18:38:31 CST 2011
[3] 368 /etc/apache2/apache2.conf
[1] active
[1] bounce
[1] corrupt
[1] defer
[1] deferred
[1] etc
[1] flush
[1] hold
[1] incoming
[1] lib
[1] maildrop
[1] pid
[1] private
[1] public
[1] saved
[1] trace
[1] usr
[1] var

如果您向我们提供您尝试的源代码,我们可以讨论它。祝您好运,- MS

=============================================== ==================================

编辑:
DN:我理解您对 1 行输出的担忧。让我们有一个小脚本...

#!/usr/bin/perl -w
foreach (1..50) {
        print "$_\n";
}

以及上述 Java 代码的编辑版本...
comLines 已更改,并且在每个 println() 之后添加了 Thread.sleep

public class MultiExec {

        private final static String[] comLines = {
                        "ls /var/spool/postfix",
                        "perl count50.pl",
                        "cat MultiExec.java",
                        "head -40 /etc/apache2/apache2.conf"};

        public void execute() {
                for (int i = 0 ; i < comLines.length ; i++) {
                        ExecutableChild ec = new ExecutableChild (i, comLines[i]);
                        new Thread (ec).start();
        }}

        public class ExecutableChild implements Runnable {

                private int prIndex;
                private String executable;

                public ExecutableChild (int k, String cmd) {
                        prIndex = k;
                        executable = cmd;
                }

                public void run () {
                        try {
                                Process child = Runtime.getRuntime().exec(executable);
                                BufferedReader br = new BufferedReader (new InputStreamReader (
                                                                child.getInputStream()));
                                for (String s = br.readLine() ; s != null ; s = br.readLine()) {
                                        System.out.println ("[" + prIndex + "] " + s);
                                        try {
                                                Thread.sleep (20);
                                        } catch (InterruptedException intex) {
                                }}
                                br.close();
                        } catch (IOException ioex) {
                                System.err.println ("IOException for process #"+
                                                                prIndex+ ": " + ioex.getMessage());
        }}}

        public static void main (String[] args) {
                new MultiExec().execute();
}}

这是现在的输出(编译/运行后)...

[0] active
[1] 1
[2] import java.io.*;
[3] #
[2]
[0] bounce
[1] 2
[3] # Based upon the NCSA server configuration files originally by Rob McCool.
[2] public class MultiExec {
[1] 3
[0] corrupt
[3] #
[1] 4
[2]
[0] defer
[3] # This is the main Apache server configuration file.  It contains the
[2]     private final static String[] comLines = {
[0] deferred
[1] 5
[3] # configuration directives that give the server its instructions.
[2]                     "ls /var/spool/postfix",
[0] etc
[1] 6
[3] # See http://httpd.apache.org/docs/2.2/ for detailed information about
[2]                     "perl count50.pl",
[0] flush
[1] 7
[3] # the directives.
[2]                     "cat MultiExec.java",
[1] 8
[0] hold
[3] #
[1] 9
[2]                     "head -40 /etc/apache2/apache2.conf"};
[0] incoming
[3] # Do NOT simply read the instructions in here without understanding
[2]
[0] lib
[1] 10
[3] # what they do.  They're here only as hints or reminders.  If you are unsure
[1] 11
[2]     public void execute() {
[0] maildrop
[3] # consult the online docs. You have been warned.
[2]             for (int i = 0 ; i < comLines.length ; i++) {
[0] pid
[1] 12
[3] #
[1] 13
[2]                     ExecutableChild ec = new ExecutableChild (i, comLines[i]);
[0] private
[3] # The configuration directives are grouped into three basic sections:
[1] 14
[2]                     new Thread (ec).start();
[0] public
[3] #  1. Directives that control the operation of the Apache server process as a
[2]     }}
[1] 15
[0] saved
[3] #     whole (the 'global environment').
[1] 16
[0] trace
[2]
[3] #  2. Directives that define the parameters of the 'main' or 'default' server,
[0] usr
[2]     public class ExecutableChild implements Runnable {
[1] 17
[3] #     which responds to requests that aren't handled by a virtual host.
[0] var
[2]
[1] 18
[3] #     These directives also provide default values for the settings
[1] 19
[2]             private int prIndex;
[3] #     of all virtual hosts.
[1] 20
[2]             private String executable;
[3] #  3. Settings for virtual hosts, which allow Web requests to be sent to
[2]
[1] 21
[3] #     different IP addresses or hostnames and have them handled by the
[1] 22
[2]             public ExecutableChild (int k, String cmd) {
[3] #     same Apache server process.
[1] 23
[2]                     prIndex = k;
[3] #
[1] 24
[2]                     executable = cmd;
[3] # Configuration and logfile names: If the filenames you specify for many
[2]             }
[1] 25
[3] # of the server's control files begin with "/" (or "drive:/" for Win32), the
[2]
[1] 26
[3] # server will use that explicit path.  If the filenames do *not* begin
[1] 27
[2]             public void run () {
[3] # with "/", the value of ServerRoot is prepended -- so "/var/log/apache2/foo.log"
[1] 28
[2]                     try {
[3] # with ServerRoot set to "" will be interpreted by the
[1] 29
[2]                             Process child = Runtime.getRuntime().exec(executable);
[3] # server as "//var/log/apache2/foo.log".
[1] 30
[2]                             BufferedReader br = new BufferedReader (new InputStreamReader (
[3] #
[1] 31
[2]                                                             child.getInputStream()));
[3]
[1] 32
[2]                             for (String s = br.readLine() ; s != null ; s = br.readLine()) {
[3] ### Section 1: Global Environment
[1] 33
[2]                                     System.out.println ("[" + prIndex + "] " + s);
[3] #
[1] 34
[2]                                     try {
[3] # The directives in this section affect the overall operation of Apache,
[1] 35
[2]                                             Thread.sleep (20);
[3] # such as the number of concurrent requests it can handle or where it

......

输入流工作正常,不认为我这里有问题。抱歉回复这么长。祝你一切顺利,并等待看到你的代码,- MS

I think you need to be careful about the scope of the IO variables. Here is a quick code that works perfectly well, with concurrent Input Streams from 4 child processes...

import java.io.*;

public class MultiExec {

        private final static String[] comLines = {
                        "date",
                        "ls /var/spool/postfix",
                        "ls -F /usr/local/bin",
                        "wc -l /etc/apache2/apache2.conf"};

        public void execute() {
                for (int i = 0 ; i < comLines.length ; i++) {
                        ExecutableChild ec = new ExecutableChild (i, comLines[i]);
                        new Thread (ec).start();
        }}

        public class ExecutableChild implements Runnable {

                private int prIndex;
                private String executable;

                public ExecutableChild (int k, String cmd) {
                        prIndex = k;
                        executable = cmd;
                }

                public void run () {
                        try {
                                Process child = Runtime.getRuntime().exec(executable);
                                BufferedReader br = new BufferedReader (new InputStreamReader (
                                                                child.getInputStream()));
                                for (String s = br.readLine() ; s != null ; s = br.readLine())
                                        System.out.println ("[" + prIndex + "] " + s);
                                br.close();
                        } catch (IOException ioex) {
                                System.err.println ("IOException for process #"+
                                                prIndex+ ": " + ioex.getMessage());
        }}}

        public static void main (String[] args) {
                new MultiExec().execute();
        }
}

Output from the above code (% javac MultiExec.java; java MultiExec)

[2] tomcat*
[0] Thu Jan 20 18:38:31 CST 2011
[3] 368 /etc/apache2/apache2.conf
[1] active
[1] bounce
[1] corrupt
[1] defer
[1] deferred
[1] etc
[1] flush
[1] hold
[1] incoming
[1] lib
[1] maildrop
[1] pid
[1] private
[1] public
[1] saved
[1] trace
[1] usr
[1] var

If you get us the source code for your attempt, we could discuss it. Good wishes, - M.S.

=============================================================================

Edit:
DN: I understand your concerns about 1-line outputs. Lets have a small script...

#!/usr/bin/perl -w
foreach (1..50) {
        print "$_\n";
}

and an edited version of the above Java Code...
comLines have changed, and a Thread.sleep added after every println()

public class MultiExec {

        private final static String[] comLines = {
                        "ls /var/spool/postfix",
                        "perl count50.pl",
                        "cat MultiExec.java",
                        "head -40 /etc/apache2/apache2.conf"};

        public void execute() {
                for (int i = 0 ; i < comLines.length ; i++) {
                        ExecutableChild ec = new ExecutableChild (i, comLines[i]);
                        new Thread (ec).start();
        }}

        public class ExecutableChild implements Runnable {

                private int prIndex;
                private String executable;

                public ExecutableChild (int k, String cmd) {
                        prIndex = k;
                        executable = cmd;
                }

                public void run () {
                        try {
                                Process child = Runtime.getRuntime().exec(executable);
                                BufferedReader br = new BufferedReader (new InputStreamReader (
                                                                child.getInputStream()));
                                for (String s = br.readLine() ; s != null ; s = br.readLine()) {
                                        System.out.println ("[" + prIndex + "] " + s);
                                        try {
                                                Thread.sleep (20);
                                        } catch (InterruptedException intex) {
                                }}
                                br.close();
                        } catch (IOException ioex) {
                                System.err.println ("IOException for process #"+
                                                                prIndex+ ": " + ioex.getMessage());
        }}}

        public static void main (String[] args) {
                new MultiExec().execute();
}}

Here is the output now (after compile/run) ...

[0] active
[1] 1
[2] import java.io.*;
[3] #
[2]
[0] bounce
[1] 2
[3] # Based upon the NCSA server configuration files originally by Rob McCool.
[2] public class MultiExec {
[1] 3
[0] corrupt
[3] #
[1] 4
[2]
[0] defer
[3] # This is the main Apache server configuration file.  It contains the
[2]     private final static String[] comLines = {
[0] deferred
[1] 5
[3] # configuration directives that give the server its instructions.
[2]                     "ls /var/spool/postfix",
[0] etc
[1] 6
[3] # See http://httpd.apache.org/docs/2.2/ for detailed information about
[2]                     "perl count50.pl",
[0] flush
[1] 7
[3] # the directives.
[2]                     "cat MultiExec.java",
[1] 8
[0] hold
[3] #
[1] 9
[2]                     "head -40 /etc/apache2/apache2.conf"};
[0] incoming
[3] # Do NOT simply read the instructions in here without understanding
[2]
[0] lib
[1] 10
[3] # what they do.  They're here only as hints or reminders.  If you are unsure
[1] 11
[2]     public void execute() {
[0] maildrop
[3] # consult the online docs. You have been warned.
[2]             for (int i = 0 ; i < comLines.length ; i++) {
[0] pid
[1] 12
[3] #
[1] 13
[2]                     ExecutableChild ec = new ExecutableChild (i, comLines[i]);
[0] private
[3] # The configuration directives are grouped into three basic sections:
[1] 14
[2]                     new Thread (ec).start();
[0] public
[3] #  1. Directives that control the operation of the Apache server process as a
[2]     }}
[1] 15
[0] saved
[3] #     whole (the 'global environment').
[1] 16
[0] trace
[2]
[3] #  2. Directives that define the parameters of the 'main' or 'default' server,
[0] usr
[2]     public class ExecutableChild implements Runnable {
[1] 17
[3] #     which responds to requests that aren't handled by a virtual host.
[0] var
[2]
[1] 18
[3] #     These directives also provide default values for the settings
[1] 19
[2]             private int prIndex;
[3] #     of all virtual hosts.
[1] 20
[2]             private String executable;
[3] #  3. Settings for virtual hosts, which allow Web requests to be sent to
[2]
[1] 21
[3] #     different IP addresses or hostnames and have them handled by the
[1] 22
[2]             public ExecutableChild (int k, String cmd) {
[3] #     same Apache server process.
[1] 23
[2]                     prIndex = k;
[3] #
[1] 24
[2]                     executable = cmd;
[3] # Configuration and logfile names: If the filenames you specify for many
[2]             }
[1] 25
[3] # of the server's control files begin with "/" (or "drive:/" for Win32), the
[2]
[1] 26
[3] # server will use that explicit path.  If the filenames do *not* begin
[1] 27
[2]             public void run () {
[3] # with "/", the value of ServerRoot is prepended -- so "/var/log/apache2/foo.log"
[1] 28
[2]                     try {
[3] # with ServerRoot set to "" will be interpreted by the
[1] 29
[2]                             Process child = Runtime.getRuntime().exec(executable);
[3] # server as "//var/log/apache2/foo.log".
[1] 30
[2]                             BufferedReader br = new BufferedReader (new InputStreamReader (
[3] #
[1] 31
[2]                                                             child.getInputStream()));
[3]
[1] 32
[2]                             for (String s = br.readLine() ; s != null ; s = br.readLine()) {
[3] ### Section 1: Global Environment
[1] 33
[2]                                     System.out.println ("[" + prIndex + "] " + s);
[3] #
[1] 34
[2]                                     try {
[3] # The directives in this section affect the overall operation of Apache,
[1] 35
[2]                                             Thread.sleep (20);
[3] # such as the number of concurrent requests it can handle or where it

......

The Input Streams are working just fine, don't think I have a problem here. Sorry about the reply getting so long. Wish you the best, and waiting to see your code, - M.S.

掀纱窥君容 2024-10-19 19:00:56

确保您在正确的范围内声明 stdErrstdIn。在这种情况下,您需要在 Y 中声明它们。

如果您在 X 中声明它们,则每次运行以下代码时:

stdErr  = process.getErrorStream();
stdIn   = process.getInputStream();

变量将被重新分配,并且 Y 的所有实例将引用相同的流。

Make sure that you are declaring stdErr and stdIn in the correct scope. In this case you need to be declaring them in Y.

If you are declaring them in X, each time you run the following code:

stdErr  = process.getErrorStream();
stdIn   = process.getInputStream();

The variables will be reassigned, and all instances of Y will reference the same stream.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文