使用Process Builder从Java进程调用的Perl脚本挂起(消耗错误,输出流在单独的线程中)

时间:2018-11-20 15:42:06

标签: java perl

我正在尝试从Java代码运行这样的perl程序:

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class PerlExecutor {

   static ExecutorService pool = Executors.newFixedThreadPool(3);

   public static void main(String[] args) throws Exception {
       System.out.println("Running perl script " + args[0]);
       executeProcess(args[0]);
       System.out.println("Done running perl script");
       pool.shutdownNow();
   }

  private static void executeProcess(String perlScript) throws Exception {

     System.out.println("Execute process " + perlScript);

     String[] command = new String[]{"perl", perlScript};
     ProcessBuilder pb = new ProcessBuilder(command);
     final Process process = pb.start();
     process.getOutputStream().close();

     Callable<Integer> callable = new Callable<Integer>() {

        public Integer call() throws Exception {
            int exitCode = process.waitFor();
            return (Integer) exitCode;
        }
    };
    Callable<Boolean> taskOutputStreamCallable = new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            System.out.println("OutputStreamCallable started");
            readStream(process.getInputStream(), "OUT");
            System.out.println("OutputStreamCallable finished");
            return true;
        }
    };

    Callable<Boolean> taskErrorStreamCallable = new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            System.out.println("ErrorStreamCallable started");
            readStream(process.getErrorStream(), "ERR");
            System.out.println("ErrorStreamCallable finished");
            return true;
        }
    };

    pool.submit(taskErrorStreamCallable);
    pool.submit(taskOutputStreamCallable);
    Future<Integer> f = pool.submit(callable);

    f.get();
}

 private static void readStream(InputStream inputStream, String type) throws 
 IOException {

    System.out.println("Reading stream " + type);

    try {

        int data = inputStream.read();
        System.out.println((char) data);
        while (data != -1) {
            System.out.println((char) data);
            data = inputStream.read();
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        inputStream.close();
    }
    System.out.println("finished reading stream");
  } 
}

这是我的perl代码:

#!/usr/local/bin/perl

print "task START \n";

$a = 10;

while(1) {
 print  "Value of a: $a\n";
 $a = $a + 1;
 sleep(10);
}

如您所见,我已经消耗了输出和错误流,并按照建议Here关闭了stdin。

我注意到的是:

  1. 如果perl程序单独运行,则不会挂起。
  2. 如果从Java运行perl程序,它将挂起,而不会从perl程序中打印任何内容。
  3. 但是,如果我在顶部的perl脚本中添加$ | ++,它将起作用。我的印象是,perl打印语句中的换行符也应刷新缓冲区,但是显然这似乎没有发生,或者我丢失了一些东西。
  4. 如果我取消睡眠,它将再次起作用。

我很困惑,到目前为止,我已经完成了我在链接中建议的所有操作。任何人都可以在这里给我一个指针吗?睡眠和缓冲区的某种组合似乎导致其失败。

0 个答案:

没有答案