Использование потоков и ProcessBuilder - PullRequest
2 голосов
/ 07 августа 2009

Я действительно незнаком с работой с потоками, поэтому я надеялся, что кто-нибудь может помочь мне найти лучший способ сделать это.

У меня есть JButton в моем java-приложении ... когда вы нажимаете на кнопку, у меня появляется Process Builder, который создает процесс, который выполняет некоторый внешний код Python. Код Python генерирует некоторые файлы, и это может занять некоторое время. Когда код Python завершен, мне нужно загрузить эти файлы в апплет в моем приложении Java.

В своем текущем виде у меня есть p.waitFor () в коде, который вызывает внешний файл python ... поэтому, когда вы нажимаете на кнопку, кнопка зависает (фактически, все приложение зависает), пока процесс сделанный. Очевидно, я хочу, чтобы пользователь мог взаимодействовать с остальной частью приложения во время этого процесса, но как только он будет завершен, я хочу, чтобы мое приложение знало об этом, чтобы оно могло загружать файлы в апплет .

Каков наилучший способ сделать это?

Спасибо за вашу помощь.

Ответы [ 2 ]

9 голосов
/ 07 августа 2009

Вы должны использовать SwingWorker для вызова процесса Python в фоновом потоке. Таким образом, ваш пользовательский интерфейс будет реагировать, пока выполняется долгосрочная задача.

// Define Action.
Action action = new AbstractAction("Do It") {
  public void actionPerformed(ActionEvent e) {
    runBackgroundTask();
  }
}

// Install Action into JButton.
JButton btn = new JButton(action);

private void runBackgroundTask() {
  new SwingWorker<Void, Void>() {
    {
      // Disable action until task is complete to prevent concurrent tasks.
      action.setEnabled(false);
    }

    // Called on the Swing thread when background task completes.
    protected void done() {
      action.setEnabled(true);

      try {
        // No result but calling get() will propagate any exceptions onto Swing thread.
        get();
      } catch(Exception ex) {
        // Handle exception
      }
    }

    // Called on background thread
    protected Void doInBackground() throws Exception {
      // Add ProcessBuilder code here!
      return null; // No result so simply return null.
    }
  }.execute();
}
0 голосов
/ 07 августа 2009

Вы действительно хотите создать новый поток для мониторинга вашего нового процесса. Как вы обнаружили, использование только одного потока как для пользовательского интерфейса, так и для мониторинга дочернего процесса может привести к зависанию пользовательского интерфейса во время выполнения дочернего процесса.

Вот пример кода, который предполагает существование логгера log4j, который, я думаю, проиллюстрирует один из возможных подходов ...

Runtime runtime = Runtime.getRuntime();
String[] command = { "myShellCommand", "firstArgument" };

try {

    boolean done = false;
    int exitValue = 0;
    Process proc = runtime.exec(command);

    while (!done) {
        try {
            exitValue = proc.exitValue();
            done = true;
        } catch (IllegalThreadStateException e) {
            // This exception will be thrown only if the process is still running 
            // because exitValue() will not be a valid method call yet...
            logger.info("Process is still running...")
        }
    }

    if (exitValue != 0) {
        // Child process exited with non-zero exit code - do something about failure.
        logger.info("Deletion failure - exit code " + exitValue);
    }

} catch (IOException e) {
    // An exception thrown by runtime.exec() which would mean myShellCommand was not 
    // found in the path or something like that...
    logger.info("Deletion failure - error: " + e.getMessage());
}

// If no errors were caught above, the child is now finished with a zero exit code
// Move on happily
...