我有一个存储对象列表的swing应用程序。当用户单击按钮时,
我想对列表中的每个对象执行两个操作,然后在完成后,将结果绘制在JPanel中。我一直在尝试SwingWorker,Callable& Runnable可以进行处理,但无论我做什么,在处理列表时(可能需要几分钟,因为它是IO绑定的),GUI被锁定。
我有一种感觉,这可能是我调用线程或其他东西的方式,还是可能与图形函数有关?这不是线程,因为它非常快。
我必须按顺序完成两个处理阶段,那么确保第二个阶段在第一阶段等待的最佳方法是什么?我使用了join(),然后是
while(x.isAlive())
{
Thread.sleep(1000);
}
试图确保这一点,但我担心这也可能是我的问题的原因。
我一直在寻找各种指针,但由于我找不到任何东西,我确定我在这里做了些蠢事。
答案 0 :(得分:18)
问题是,您的长时间运行任务阻止了保持GUI响应的线程。
您需要做的是将长时间运行的任务放在另一个线程上。
执行此操作的一些常用方法是使用计时器或SwingWorker
。
Java tutorials在他们的并发课程中有很多关于这些事情的信息。
要确保第一个任务在第二个任务之前完成,只需将它们放在同一个线程上即可。这样你就不必担心保持两个不同的线程正确计时。
以下是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.
}
}
要使用此代码,当触发修改列表的事件时,请创建一个新的SwingWorker
并告诉它开始。
答案 1 :(得分:6)
您没有正确返回摆动线程。我意识到你正在使用可调用/可运行但我猜你做得不对(虽然你没有发布足够的代码来确定)。
基本结构如下:
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,则该线程不会返回给系统!
编辑:(实际上是第二次编辑) 我想谈谈你实际感受到的问题 - 你可能想要更多地考虑模型/视图/控制器系统。您正在编写的代码是控制器(视图通常被认为是屏幕上的组件 - 视图/控制器通常非常紧密地绑定)。
当你的控制器获得事件时,它应该将工作传递给你的模型。然后视图就不在了。它不会等待模型,它刚刚完成。
当你的模型完成后,它需要告诉控制器做其他事情。它通过一种调用方法完成此操作。这会将控制权转移回控制器,然后继续你的快乐方式。如果以这种方式考虑它,分离控制并故意来回传递它并不会感觉太笨重,而且这样做实际上很常见。
答案 2 :(得分:1)
听起来问题可能是你正在等待线程从GUI线程内部完成。您的GUI线程不应该等待这些线程,而应该让工作线程在GUI线程上调用一些设置标志的方法。设置两个标志后,您就知道两个线程都已完成,您可以执行图形。
答案 3 :(得分:0)
我无法真正对摇摆线程模型说话,但是:
我必须按顺序完成两个处理阶段,那么确保第二个阶段在第一阶段等待的最佳方法是什么?
对于这种功能,我建议你创建两个工作线程,并嵌入一个JMS代理。通过将消息传递到它们读取的JMS队列,将工作交付给两个线程。您的GUI线程可以自由检查队列以确定何时发生工作并表示您的UI中的游戏状态。
答案 4 :(得分: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本身没有完成所有工作,这可能是一个问题。