Хранение строк в ArrayList в синхронизированном методе - PullRequest
0 голосов
/ 01 апреля 2020

Итак, у меня есть эта программа, которая выполнит команду в cmd, а затем получит ее вывод. Выходные данные собираются внутри метода log (). Первоначально я распечатывал вывод, и он печатался нормально. Затем я также хотел сохранить вывод в ArrayList. По какой-то причине при сохранении его в ArrayList добавляется только первая строка, а при печати печатаются все строки.

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;

public class Executor {
    private ArrayList<String> currentOutput = new ArrayList<String>();
    public void executeCommand(String command) {
        command = "cmd /c "+ command;
        try {
            log(command);
            Process process = Runtime.getRuntime().exec(command);
            logOutput(process.getInputStream(), "");
            logOutput(process.getErrorStream(), "Error: ");
            process.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void logOutput(InputStream inputStream, String prefix) {
        new Thread(() -> {
            Scanner scanner = new Scanner(inputStream, "UTF-8");
            while (scanner.hasNextLine()) {
                synchronized (this) {

                    log(prefix + scanner.nextLine());
                }
            }
            scanner.close();
        }).start();
    }



    private synchronized void log(String message) {
        currentOutput.add(message);    // Only adds the output the first time the method is called
        System.out.println(message);   // Prints out all of the outputs
    }

    public ArrayList<String> getOutput() {
        return currentOutput;
    }
}

1 Ответ

0 голосов
/ 01 апреля 2020

Вы не ждете, пока 2 потока завершат свою работу.

Вам нужно изменить logOutput(), чтобы вернуть объект Thread, и вам нужно вызвать join() в 2 возвращенных потоках сразу после вызова waitFor().

public void executeCommand(String command) {
    ...
    Thread t1 = logOutput(process.getInputStream(), "");
    Thread t2 = logOutput(process.getErrorStream(), "Error: ");
    process.waitFor();
    t1.join();
    t2.join();
    ...
}

private Thread logOutput(InputStream inputStream, String prefix) {
    Thread t = ...
    t.start();
    return t;
}

Кроме того, этот код является избыточным, поскольку метод log() равен synchronized. Снимите блок synchronized (this).

...
synchronized (this) {
    log(prefix + scanner.nextLine());
}
...
...