Приостановить дальнейшее выполнение, если поток не завершен

#java

#java

Вопрос:

Я написал программу, которая выполняет команду cmd и выводит выходные данные на «консоль» программы. Я использовал поток для печати выходных данных без замораживания программы. Я хочу иметь возможность видеть вывод в реальном времени.

Что с этим не так, и я не могу найти решение для этого, так это то, что часть в initialize сразу после executeCommand вызова метода выполняется сразу после ExecuteCommand . Что я хочу иметь возможность сделать, так это выполнить остальную часть инициализации, как только поток перестанет выполняться. Я не могу этого сделать, не заморозив всю программу.

Я использовал метод объединения потоков и аналогичный, но мое приложение просто полностью зависает.

Это мой основной класс

 private String genCmd2;

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                ConvertGUI window = new ConvertGUI();
                window.frmConvert.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public ConvertGUI() {
    initialize();
}

private void initialize() {
     // Execute a generated command concurrently
    genCmd2 = "ping google.com -n 5";
    executeCommand(genCmd2, genCmdTextArea);

    //CODE TO RUN AFTER EXECUTE COMMAND IS FULLY FINISHED
    //NOT RIGHT AFTER executeCommand method is called

}

public static void printToTheConsole(JTextArea console, String message) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            console.append(message);
            console.validate();
        }
    });
}

private static void executeCommand(String command, JTextArea console) {
    Runnable r = new CommandLineRunnable(command, console);
    t = new Thread(r);
    t.start();
}
  

Мой исполняемый класс, который выполняет команду и выводит данные на консоль

 public class CommandLineRunnable extends ConvertGUI implements Runnable {
    private String generatedCommand;
    private JTextArea console;

    public CommandLineRunnable(String command, JTextArea console) {
        this.generatedCommand = command;
        this.console = console;
        printToTheConsole(console, command);
    }

    @Override
    public void run() {
        StringBuilder output = new StringBuilder();
        BufferedReader reader;
        Process process;
        try {
            process = Runtime.getRuntime().exec(generatedCommand);
            reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;

            while ((line = reader.readLine()) != null) {
                output.append(line   "n");
                printToTheConsole(console, line   "n");
            }

            printToTheConsole(console, "n--------------------------Success!--------------------------n");

            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
  

Ответ №1:

Если вы хотите выполнить печать на консоль, обновить JTextArea во время и после того, как одна из ваших выполняемых # задач была (не) успешно выполнена, вы могли бы реализовать интерфейс и предоставить его вашему конструктору Runnables

Рассмотрим следующий пример, в котором создается экземпляр класса CommandLineRunnable со строкой аргументов ‘aCommand’ в качестве команды, объектом JTextArea ‘console’ и новым анонимным классом ResponseEvent в качестве его параметров.

Обратите внимание, что из-за дублирования в анонимном классе, если вы выполняете несколько команд, скорее всего, вы не захотите создавать экземпляр анонимного класса несколько раз и могли бы просто вставить код printToTheConsole внутри методов функционального интерфейса

     public static void main(String[] args) {

        JTextArea console = new JTextArea();

        /**
         * JTextArea init code here
         */

        executeCommand("aCommand", console, new ResponseEvent() {

            @Override
            public void onSuccess(JTextArea console, String response) {
                printToTheConsole(console, response);
            }

            @Override
            public void onUpdate(JTextArea console, String response) {
                printToTheConsole(console, response);
            }

            @Override
            public void onFailure(JTextArea console, String response) {
                printToTheConsole(console, response);
            }
        });
    }

    private static void printToTheConsole(JTextArea console, String message) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                console.append(message);
                console.validate();
            }
        });
    }

    private static void executeCommand(String command, JTextArea console, ResponseEvent event) {
        Runnable r = new CommandLineRunnable(command, console, event);
        Thread thread = new Thread(r);
        thread.start();
    }

    @FunctionalInterface
    private interface ResponseEvent {
        default void onSuccess(JTextArea console, String response) {

        }

        default void onUpdate(JTextArea console, String response) {

        }

        default void onFailure(JTextArea console, String response) {

        }

    }

    public static class CommandLineRunnable implements Runnable {

        private final String command;
        private final ResponseEvent event;
        private final JTextArea console;

        public CommandLineRunnable(String command, JTextArea console, ResponseEvent event) {
            this.command = command;
            this.console = console;
            this.event = event;
        }

        public ResponseEvent getEvent() {
            return event;
        }

        @Override
        public void run() {
            Process process;
            BufferedReader reader = null;
            try {
                process = Runtime.getRuntime().exec(getCommand());
                reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

                String line;

                while ((line = reader.readLine()) != null) {
                    getEvent().onUpdate(getConsole(), line   "n");
                }

                getEvent().onSuccess(getConsole(), "n--------------------------Success!--------------------------n");
            } catch (IOException e) {
                getEvent().onFailure(getConsole(), "n--------------------------Failure!--------------------------n");
            }
        }

        private JTextArea getConsole() {
            return console;
        }

        private String getCommand() {
            return command;
        }
    }
  

После выполнения, которое может произойти в любое время, будет выполнена выполняемая функция#run().

Код будет запущен и будет вызван либо метод ResponseEvent#onSuccess, либо метод ResponseEvent#OnFailure

Затем вы можете обрабатывать ответы так, как хотите, возможно, обновив одну из ваших JTextAreas

Комментарии:

1. Я не хочу выводить данные на консоль после успешного выполнения одной из моих выполняемых задач. Я хочу вывести на консоль, как только какой-либо вывод будет обнаружен во время выполнения команды, в реальном времени. Что я хочу сделать после завершения задачи, так это выполнить код после вызова ExecuteCommand. Что-нибудь вроде System.out.println(«Привет») должно ждать, пока поток завершит свою работу. Если вы посмотрите, что находится внутри initialize() , там есть 2 строки комментариев. Я хочу, чтобы это подождало, пока поток не завершится.

2. @LazioTibijczyk хорошо, я сделал это более применимым к вашим обстоятельствам 🙂