首页 > 解决方案 > 为什么 Java 并行文件写入不起作用?

问题描述

我正在尝试编写一个脚本,该脚本将使用不同的参数运行 .exe 程序 4 次。我为每个 .exe 运行创建了一个线程。每个线程将写入一个输出文件。我的问题是,它应该并行写入,但正如您在下面的屏幕截图中看到的那样,文件一个接一个地写入。这应该如何解决?

在此处输入图像描述

下面是主要方法:

public static void main (String args[]) {
    ExecutorService executor = Executors.newFixedThreadPool(4);
    executor.execute(new RunnableReader("myprogram.exe", param1, outputFile1));
    executor.execute(new RunnableReader("myprogram.exe", param2, outputFile2));
    executor.execute(new RunnableReader("myprogram.exe", param3, outputFile3));
    executor.execute(new RunnableReader("myprogram.exe", param4, outputFile4));
    executor.shutdown();
}

这是可运行的类:

public class RunnableReader implements Runnable {
    private String program;
    private String param;
    String outputFile;

    public RunnableReader(String program, String param, String outputFile) {
        this.program = program;
        this.param = param;
        this.outputFile = outputFile;
    }

    @Override
    public void run() {
        try {
            ProcessBuilder pb = new ProcessBuilder(program, param);
            pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
            pb.redirectErrorStream(true);
            Process proc = pb.start();
            InputStream stream = proc.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
            BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile, true));
            for(String output; (output = reader.readLine()) != null) {
                writer.append(output);
                writer.append("\n");
            }
            writer.close();
            reader.close();
            stream.close();
  
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

标签: javamultithreadingthreadpoolbufferedwriter

解决方案


我自己无法对此进行测试,也不知道它是否真的会导致执行阻塞。但是对于它的价值,我认为我应该指出您InputStream可能没有必要阅读该过程。

正如Oracle 文档 ProcessBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE)所述,导致Process.getInputStream()返回进程的标准输出。

考虑到这一点,您可以摆脱整个for-loop,而只是做类似的事情,ProcessBuilder.redirectOutput(new File(outputFile))以便您的方法看起来像这样

@Override
public void run() {
    try {
        ProcessBuilder pb = new ProcessBuilder(program, param);
        pb.redirectOutput(new File(outputFile));
        pb.redirectErrorStream(true);
        Process proc = pb.start();
    } catch(IOException e) {
        e.printStackTrace();
    }

推荐阅读