2009-06-02 38 views
11

我有一个用于存储对象列表的swing应用程序。当用户点击一个按钮时,我想对列表中的每个对象执行两个操作,然后一旦完成,就将结果绘制在JPanel中。我一直在尝试SwingWorker,Callable & Runnable可以执行处理,但无论我在做什么,处理列表(可能需要几分钟,因为它是IO绑定),GUI都会被锁定。防止在后台任务期间锁定Swing GUI

我有一种感觉,这可能是我打电话给线程的方式,或者它可能是做图形功能?这不是线程,因为它非常快。

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

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

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

我一直在寻找一些指针,但因为我找不到任何我相信我在这里做一些愚蠢的事情。

+2

如果您包含一些代码来显示您如何使用SwingWorker,可能会有所帮助。 – 2009-06-02 18:00:20

+0

同意;向我们展示有问题的代码。 – Rob 2009-06-03 23:27:39

回答

18

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

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

这样做的一些常见方法是使用定时器或SwingWorker

Java tutorials有很多关于这些东西在他们的课程中并发的信息。

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

这里是一个SwingWorkerFor你的情况的样本实现:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> { 
    private List<Object> list 
    public YourClassSwingWorker(List<Object> theOriginalList){ 
     list = theOriginalList; 
    } 

    @Override 
    public List<Object> 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,并告诉它启动。

+1

我很确定这个问题已经提到了线程和SwingWorker。此外,SwingUtilities.invokeLater()在GUI线程上运行。 – Powerlord 2009-06-02 17:52:04

+0

是啊,我给了一个'通用的摆动线程答案...有点很烂 – jjnguy 2009-06-02 17:54:23

5

您没有正确地返回摆动螺纹。我意识到你正在使用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,则线程不会被返回到系统!

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

当你的控制器得到事件时,它应该把工作交给你的模型。该视图然后不在图片中。它不等待模型,它只是完成。

当你的模型完成后,它需要告诉控制器做其他事情。它通过其中一个调用方法来完成。这将控制权交还给控制器,然后继续您的快乐。如果你这样想,分离控制和故意传递它并不会太笨重,而且这样做实际上很常见。

1

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

0

我真的不能给回转线程模型说话,但:

我必须做的两个处理阶段,以便太多,所以什么是保证第二个最好的办法已经娇娇首先?

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

0

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

public class Worker extends SwingWorker<Void, Void> 
{ 
    private List<Object> list; 
    public YourClassSwingWorker(List<Object> theOriginalList){ 
     list = theOriginalList; 
    } 

    @Override 
    public List<Object> 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类本身没有做所有的工作,这可能是一个问题。