在没有JFrame冻结的情况下在Java中执行进程

如何在没有程序冻结的情况下在Java中执行进程? 我尝试过使用SwingWorker,但我还不太明白它是如何工作的。

还有其他方法我可以做到这一点吗? 我想在我的JDroidLib中使用这样的东西。 有关完整源代码,请查看GitHub: http : //github.com/Team-M4gkBeatz/JDroidLib

提前致谢!

编辑:

谢谢你的回答。 但是我有一个有几种方法的课(好吧,它不止一个课,但你明白我的观点); 我如何使用SwingWorker与这些进行交互?

这是其中一个类:

/** * * @author Simon */ public abstract class Command extends SwingWorker { BufferedReader prReader = null; ProcessBuilder process = null; Process pr = null; Date timeNow = new Date(); String osName = System.getProperty("os.name"); public void executeProcessNoReturn(String _process, String arg) throws IOException { process = new ProcessBuilder(_process, arg); pr = process.start(); } public String executeProcessReturnLastLine(String _process, String arg) throws IOException { process = new ProcessBuilder(_process, arg); pr = process.start(); prReader = new BufferedReader(new InputStreamReader(pr.getInputStream())); String line; while ((line = prReader.readLine()) != null) { // Wait for input to end. } return line; } public StringBuilder executeProcessReturnAllOutput(String _process, String arg) throws IOException { process = new ProcessBuilder(_process, arg); pr = process.start(); prReader = new BufferedReader(new InputStreamReader(pr.getInputStream())); StringBuilder output = null; String line; while ((line = prReader.readLine()) != null) { output.append(line); } return output; } public boolean isProcessRunning(String processName) throws IOException { boolean value = false; if (osName.equals("Linux") | osName.contains("Mac")) { process = new ProcessBuilder("ps", "-e"); pr = process.start(); String line; prReader = new BufferedReader(new InputStreamReader(pr.getInputStream())); while ((line = prReader.readLine()) != null) { if (line.contains(processName)) { value = true; break; } } } else { String winDir = System.getenv("windir") + "/System32/tasklist.exe"; process = new ProcessBuilder(winDir); pr = process.start(); String line; prReader = new BufferedReader(new InputStreamReader(pr.getInputStream())); while ((line = prReader.readLine()) != null) { if (line.contains(processName)) { value = true; break; } } } return value; } public String executeProcessReturnError(String processName, String arg) throws IOException { process = new ProcessBuilder(processName, arg); process.redirectError(); pr = process.start(); prReader = new BufferedReader(new InputStreamReader(pr.getErrorStream())); String line; String output = ""; while ((line = prReader.readLine()) != null) { output += line + "\n"; } return output; } } 

是的,你可以使用SwingWorker这个想法是一个任务,你需要花费大量的时间在一个单独的线程(后台线程)中运行,然后你不会阻止你的gui和你的JFrame不会冻结。 这是一个完整的例子,我非常喜欢Swing Worker Example 。

基本上作为示例,您可以创建自己的类,以扩展SwingWorker覆盖doInBackground

注意:您可以使用普通类等字段。

示例:

 class Worker extends SwingWorker { private SomeClass businessDelegate; private JLabel label; @Override protected Void doInBackground() throws Exception { //here you make heavy task this is running in another thread not in EDT businessDelegate.callSomeService(); setProgress(30); // this is if you want to use with a progressBar businessDelegate.saveToSomeDataBase(); publish("Processes where saved"); return null; } @Override protected void process(List chunks){ //this is executed in EDT you can update a label for example label.setText(chunks.toString()); } //add setters for label and businessDelegate } 

您还阅读了有关process(..) publish(..)done()

并在您的客户端代码中放置。

 SwingWorker myWorker = new Worker(); myWorker.execute(); 

您需要在单独的线程中运行代码。 在程序中运行和协调多个代码路径的关键字是“并发”:

http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html

multithreading代码可能变得非常棘手且难以调试,但Java提供了一些更高级别的抽象/概念,这使得使用multithreading代码更不容易出错。

看看这些概念的java.util.concurrent包。

由于multithreading是一个在使用AWT / Swing时遇到的问题,因此有一些实用程序类/方法专门用于促进图形应用程序中的multithreading。 SwingWorker就是其中之一(另一个是例如SwingUtilities.invokeLater() )。 熟悉它们将是一个好主意,它们可以让您的生活更轻松,特别是对于足够长的简单任务来冻结GUI。

如果您使用Swing,可以使用SwingWorker 。

既然你提到你不明白它是如何工作的,我会给出一个简单的解释。

Swing事件处理代码在事件派发线程中完成 。 因此,如果用户单击按钮(例如更新按钮从服务器获取数据并在窗口中显示它们),则在事件调度线程中调用该按钮的ActionListener。

如果您在同一个线程中获取数据,那么UI将冻结,因为它无法处理任何事件(您在事件派发线程中运行代码)。

所以你应该在一个单独的线程中获取数据。 但是在获取数据之后,您应该将其设置为事件派发线程中的视图。

Swing工作人员让您轻松上手。 你把繁重的任务放在doInBackground方法中(在我们的例子中是获取数据)并从方法中返回繁重任务的输出(在我们的例子中是数据)。

在swing worker的done方法中,您调用get方法,该方法将为您提供doInBackground方法中返回的数据。 在那里,您使用新数据更新视图(例如,将数据添加到TableModel)。

当你现在在你的swing worker上调用exectue时,它将doInBackground在一个单独的线程(不是Event Dispatch Thread)中运行doInBackground ,它将在事件调度线程中运行done方法。

因此,通过使用SwingWorker,您不必担心在EDT中处理UI事件的内部以及在另一个线程中耗时的任务。