Java 防止后台任务期间Swing GUI锁定
我有一个swing应用程序,它存储对象列表。当用户点击一个按钮时 我想对列表中的每个对象执行两个操作,完成后,在JPanel中绘制结果。我一直在尝试SwingWorker、Callable&Runnable进行处理,但无论我做什么,在处理列表时(可能需要几分钟,因为它是IO绑定的),GUI都被锁定 我有一种感觉,这可能是我调用线程或其他东西的方式,或者可能与图形功能有关?这不是线程,因为它非常快 我也必须按顺序完成这两个处理阶段,那么确保第二个处理阶段等待第一个处理阶段的最佳方法是什么?我使用了join(),然后Java 防止后台任务期间Swing GUI锁定,java,multithreading,swing,swingworker,event-dispatch-thread,Java,Multithreading,Swing,Swingworker,Event Dispatch Thread,我有一个swing应用程序,它存储对象列表。当用户点击一个按钮时 我想对列表中的每个对象执行两个操作,完成后,在JPanel中绘制结果。我一直在尝试SwingWorker、Callable&Runnable进行处理,但无论我做什么,在处理列表时(可能需要几分钟,因为它是IO绑定的),GUI都被锁定 我有一种感觉,这可能是我调用线程或其他东西的方式,或者可能与图形功能有关?这不是线程,因为它非常快 我也必须按顺序完成这两个处理阶段,那么确保第二个处理阶段等待第一个处理阶段的最佳方法是什么?我使用了
while(x.isAlive())
{
Thread.sleep(1000);
}
试图确保这一点,但我担心这也可能是我问题的原因
我一直在到处寻找一些指针,但由于找不到任何指针,我确信我在这里做了一些愚蠢的事情。问题是,您长期运行的任务正在阻塞线程,从而使GUI保持响应 您需要做的是将长时间运行的任务放在另一个线程上 一些常用的方法是使用定时器或定时器 在他们的并发课程中,有很多关于这些事情的信息 要确保第一个任务在第二个任务之前完成,只需将它们放在同一个线程上。这样,您就不必担心两个不同线程的计时是否正确 以下是您案例中SwingWorker的示例实现:
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.
}
}
public类YourTaskSwingWorker SwingWorker扩展SwingWorker{
私人名单
public YourClassSwingWorker(列出原始列表){
列表=原始列表;
}
@凌驾
公共列表doInBackground(){
//做列表上的第一个操作
//做清单上的第二项操作
退货清单;
}
@凌驾
公众假期结束(){
//使用更新的列表更新GUI。
}
}
要使用此代码,当触发修改列表的事件时,创建一个新的
SwingWorker
,并告诉它开始。您没有正确返回swing线程。我知道您正在使用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线程上设置标志的某个方法。当两个标志都设置好后,您就知道两个线程都完成了,并且可以绘制图形。我不能真正谈论swing线程模型,但是: 我也必须按顺序完成这两个处理阶段,那么确保第二个处理阶段等待第一个处理阶段的最佳方法是什么
对于这种功能,我建议您创建两个工作线程,并嵌入一个JMS代理。通过将消息传递到从中读取的JMS队列,将工作传递给这两个线程。您的GUI线程可以自由地检查队列,以确定工作何时发生,并表示UI中的播放状态。我的问题的解决方案是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();
}
公共类Worker扩展SwingWorker
{
私人名单;
public YourClassSwingWorker(列表理论原始列表){
列表=原始列表;
}
@凌驾
公共列表doInBackground(){
线程t=新线程(新处理器读取(列表));
t、 start();
}
@凌驾
公众假期结束(){
//在GUI上绘制图形
}
}
类ProcessorThread实现可运行的{
//做很多事情
线程t2=新线程(新的SecondProcess());
t2.start();
}
这确保了所有的工作都是由远离GUI的工作线程完成的,同时也确保SwingWorker本身没有完成所有的工作,这可能是一个问题。我很确定这个问题已经提到了线程和SwingWorker。另外,SwingUtilities.invokeLater()在GUI线程上运行。是的,我给出了一个类似于“通用swing线程”的答案……有点糟糕,我昨天懒得查找Javadoc,但我现在看到第二个类型参数仅用作publish()和process()的参数。我收回我的第一条评论