我已经更新了这个问题,使用建议的SwingWorker类包含Java实现的源代码,以完成与Objective-C示例相同的结果。希望这对未来的冒险家有所帮助。
Document myDoc = ...;
Model myModel = ...;
SwingWorker analyzeDocument = new SwingWorker<Dictionary, Void>() {
@Override
public Dictionary doInBackground() {
return myDoc.analyze();
}
@Override
public void done() {
try {
stats = get();
myModel.setDict(stats);
myModel.setNeedsDisplay(true);
} catch(InterruptedException ex) {
// log
} catch(ExecutionException ex) {
// log
}
}
};
analyzeDocument.execute();
在并发编程方面,我缺乏经验,我希望有人能够向我解释如何实现这一目标。
在Objective-C(使用GCD)中,您可以执行以下操作:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
NSDictionary *stats = [myDoc analyze];
dispatch_async(dispatch_get_main_queue(), ^{
[myModel setDict:stats];
[myStatsView setNeedsDisplay:YES];
[stats release];
});
});
此代码将在后台线程中执行[myDoc analyze]
,跟随回调函数更新将在主线程中执行的UI。换句话说,后台线程向主线程发送一个中断,将匿名函数添加到要调用的主线程队列中。显然我不能在Java中使用匿名函数,但这不是重点。
我有兴趣在Java中做这件事。我有一个Runnable
对象在文件系统中执行一堆东西。完成后,我想相应地更新UI。
为了在执行此操作时不挂起主线程(即:backgroundThread.join();
),我设置了后台线程来执行回调函数来更新UI。但这不是一个好主意,我不希望非GUI线程更新GUI。
我想到的其他一些想法是投票,但这似乎就是抛出一些循环。根据同样的判断,使用期货似乎也不是答案。这一切似乎都打败了异步行动的目的。
我唯一能想到的是从后台线程中使用SwingUtilities.invokeLater
并使用它来更新GUI。但我很好奇这将执行哪个线程。
也许我的看法只是扭曲了,但这似乎是一个非常重要的部分。我只是想以错误的方式解决这个问题吗?
答案 0 :(得分:6)
您是否考虑过创建和使用SwingWorker
对象?这允许您轻松地在事件线程的线程背景中运行代码,并且实际上也是Future对象,因此它可以返回结果,并且您可以在其done()
方法中使用此结果来更新事件线程上的GUI。您甚至可以通过publish
/ process
方法对在运行过程中对Swing事件线程进行调用。
有关详情,请查看:Concurrency in Swing
答案 1 :(得分:2)
如果您使用Callable<V>
代替Runnable
,则可以返回一个值。
另外,请查看课程Executors
。