防止在后台任务期间锁定Swing GUI

我有一个swing应用程序,它存储一个对象列表。 当用户点击按钮时

我想对列表中的每个对象执行两个操作,然后在完成后,将结果绘制在JPanel中。 我一直在尝试使用SwingWorker,Callable和Runnable进行处理,但无论我做什么,在处理列表时(可能需要几分钟,因为它是IO绑定的),GUI被锁定。

我有一种感觉,这可能是我调用线程或其他东西的方式,还是可能与图形函数有关? 这不是线程,因为它非常快。

我必须按顺序完成两个处理阶段,那么确保第二个阶段在第一个阶段等待的最佳方法是什么? 我已经使用了join(),然后

while(x.isAlive()) { Thread.sleep(1000); } 

试图确保这一点,但我担心这也可能是我的问题的原因。

我一直在寻找一些指针,但由于我找不到任何东西,我确信我在这里做了些蠢事。

问题是,您的长时间运行任务阻止了保持GUI响应的线程。

您需要做的是将长时间运行的任务放在另一个线程上。

一些常见的方法是使用Timers或SwingWorker

Java教程在他们的并发课程中有很多关于这些内容的信息。

要确保第一个任务在第二个任务之前完成,只需将它们放在同一个线程上即可。 这样你就不必担心保持两个不同的线程正确计时。

以下是SwingWorker的示例实现:

 public class YourTaskSwingWorkerSwingWorker extends SwingWorker, Void> { private List list public YourClassSwingWorker(List theOriginalList){ list = theOriginalList; } @Override public List doInBackground() { // Do the first opperation on the list // Do the second opperation on the list return list; } @Override public void done() { // Update the GUI with the updated list. } } 

要使用此代码,当触发修改列表的事件时,请创建一个新的SwingWorker并告诉它启动。

你没有正确地返回摆动螺纹。 我意识到你正在使用callable / runnable但我猜你做得不对(虽然你没有发布足够的代码来确定)。

基本结构如下:

 swingMethod() { // Okay, this is a button callback, we now own the swing thread Thread t=new Thread(new ActuallyDoStuff()); t.start(); } public class ActuallyDoStuff() implements Runnable { public void run() { // this is where you actually do the work } } 

这只是我的头脑,但我猜你要么不是在做thread.start而是直接调用run方法,要么在第一个锁定它的方法中做其他事情(喜欢thread.join)。 这些都不会释放挥杆线程。 第一种方法必须快速返回,run()方法可以随意返回。

如果您在第一个方法中执行thread.join,则该线程不会返回给系统!

编辑:(实际上是第二次编辑)我想谈谈你实际感受到的问题 – 你可能想要更多地考虑模型/视图/控制器系统。 您正在编写的代码是控制器(视图通常被认为是屏幕上的组件 – 视图/控制器通常非常紧密地绑定)。

当您的控制器获取事件时,它应该将工作传递给您的模型。 然后视图就不在了。 它不等待模型,它刚刚完成。

模型完成后,需要告诉控制器执行其他操作。 它通过一种调用方法完成此操作。 这会将控制权转移回控制器,然后以快乐的方式进行。 如果以这种方式考虑它,分离控制并故意来回传递它并不会感觉太笨重,而且这样做实际上很常见。

听起来问题可能是您正在等待线程从GUI线程内部完成。 您的GUI线程不应该等待这些线程,而应该让工作线程在GUI线程上调用一些设置标志的方法。 设置两个标志后,您就知道两个线程都已完成,您可以执行图形。

我真的不能说摇摆线程模型,但是:

我必须按顺序完成两个处理阶段,那么确保第二个阶段在第一个阶段等待的最佳方法是什么?

对于这种function,我建议你创建两个工作线程,并嵌入一个JMS代理。 通过将消息传递到它们读取的JMS队列,将工作交付给两个线程。 您的GUI线程可以自由检查队列以确定何时发生工作并表示UI中的播放状态。

我的问题的解决方案是jjnguy和Bill K的答案的混合,所以非常感谢那些家伙。 我需要在SwingWorker中使用这样的线程:

 public class Worker extends SwingWorker { private List list; public YourClassSwingWorker(List theOriginalList){ list = theOriginalList; } @Override public List doInBackground() { Thread t = new Thread(new ProcessorThread(list)); t.start(); } @Override public void done() { // draw graph on GUI } } class ProcessorThread implements Runnable { //do lots of IO stuff Thread t2 = new Thread(new SecondProcess()); t2.start(); } 

这确保了工作线程远离GUI完成所有工作,并确保SwingWorker本身没有完成所有工作,这可能是一个问题。