使用线程和ProcessBuilder

时间:2009-08-07 16:46:14

标签: java multithreading process processbuilder

我对使用线程非常不熟悉,所以我希望有人可以帮我找出最好的方法。

我的java应用程序中有一个JButton ...当你点击按钮时,我有一个Process Builder,它创建一个执行一些外部python代码的进程。 python代码生成一些文件,这可能需要一些时间。当python代码完成执行时,我需要将这些文件加载​​到我的Java应用程序中的applet中。

在目前的形式中,我在调用外部python文件的代码中有一个p.waitFor()...所以当你点击按钮时,按钮挂起(整个应用程序实际挂起)直到进程是完成。显然,我希望用户能够在此过程进行时与应用程序的其余部分进行交互,但是一旦完成,我希望我的应用程序知道它,以便它可以将文件加载到applet中

最好的方法是什么?

感谢您的帮助。

2 个答案:

答案 0 :(得分:9)

您应该使用SwingWorker在后台线程上调用Python进程。这样,在长时间运行的任务运行时,您的UI将保持响应。

// 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();
}

答案 1 :(得分:0)

您真的想要创建一个新线程来监控您的新流程。正如您所发现的那样,在UI和监视子进程时只使用一个线程将使子进程运行时UI似乎挂起。

这是一些示例代码,假设存在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