据我所知,它用于在 Swing 应用程序中调度一个新线程以执行一些“后台”工作,但是使用它而不是“普通”线程有什么好处?
使用新线程和使用 SwingUtilities.invokeLater 完成调用某些 GUI 方法时不一样吗?...
我在这里想念什么?
http://en.wikipedia.org/wiki/SwingWorker
http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
据我所知,它用于在 Swing 应用程序中调度一个新线程以执行一些“后台”工作,但是使用它而不是“普通”线程有什么好处?
使用新线程和使用 SwingUtilities.invokeLater 完成调用某些 GUI 方法时不一样吗?...
我在这里想念什么?
http://en.wikipedia.org/wiki/SwingWorker
http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
是的,您可以使用普通线程 + invokeLater 完成 SwingWorker 所做的事情。SwingWorker 提供了一种可预测的集成方式来在后台线程上完成任务并在 EDT 上报告结果。SwingWorker 还添加了对中间结果的支持。同样,您可以自己完成所有这些工作,但有时使用集成且可预测的解决方案很容易,尤其是在并发方面。
代码示例:
import org.jdesktop.swingx.util.SwingWorker; // This one is from swingx
// another one is built in
// since JDK 1.6 AFAIK?
public class SwingWorkerTest {
public static void main( String[] args ) {
/**
* First method
*/
new Thread() {
public void run() {
/** Do work that would freeze GUI here */
final Object result = new Object();
java.awt.EventQueue.invokeLater( new Runnable() {
public void run() {
/** Update GUI here */
}
} );
}
}.start();
/**
* Second method
*/
new SwingWorker< Object , Object >() {
protected Object doInBackground() throws Exception {
/** Do work that would freeze GUI here */
return null;
}
protected void done() {
try {
Object result = get();
/** Update GUI here */
}
catch ( Exception ex ) {
ex.printStackTrace();
if ( ex instanceof java.lang.InterruptedException )
return;
}
}
}.execute();
}
}
选择始终取决于个人偏好和用例。
第二种方法在重构时具有优势。当使用的方法太大时,您可以更轻松地将匿名类转换为内部类。
我个人偏好第二种,因为我们已经构建了一个框架,可以在其中添加 SwingWorkers 并一个接一个地执行......
SwingWorker 是一种通用模式的实现(在 .Net 中我读到有GuiWorker BackgroundWorker 为此),您必须在 GUI 程序中做一些工作,但要保持 GUI 响应。问题是 GUI 库通常不是多线程安全的,因此实现此类工作器的常用方法是使用库的消息循环将消息传递到应用程序的事件循环中。
这些类允许您轻松更新您的 GUI。通常,它们有一个update(int status)
由线程调用、由类分派并由 GUI 处理的方法,同时线程继续其工作。
使用普通线程,您将需要为此任务编写自己的事件或一些其他消息传递机制,如果您经常需要此功能,这可能会很痛苦。例如,在 Java 中使用 invokeLater,您可以将用于更新 gui 的代码混合到用于完成工作的代码中。SwingWorker 允许您将事物分开。
回答你的问题,你没有错过任何东西。这个类只是一个方便的实用程序,用于包装您描述的功能(启动另一个线程来完成后台工作,然后在 EDT 上调用一些最终操作并使用结果)。
使用 Swing 时,重要的是要知道主要的 Swing 处理(即渲染)发生在单个线程上(这不是您的主线程)。这通常称为 Swing 或 awt 事件线程。那些熟悉 JDK pre 1.6 的人会记得如果您在事件调度程序中花费太多时间来处理 swing 组件的“灰色矩形”错误。这是什么意思。在任何 Swing 应用程序中,您将运行 2 个线程,您现在必须处理这些线程。通常,如果您在事件调度程序中的所有操作(当单击按钮时触发的代码)都很短(即更改 siwng 按钮的状态),您可以在事件调度程序内部运行它。如果您的应用程序将调用 Web 服务或数据库,或者您的应用程序状态由外部事件驱动(即。jms)或者您只想使您的 UI 更具交互性(即构建项目列表并能够做其他事情),您应该使用 awt 事件线程(主要摆动线程)以外的线程。因此,在这些情况下,您会生成一个新线程并执行您必须执行的操作,当结果最终返回时,您必须以某种方式创建一个可由 awt/swing 调度程序执行的事件。SwingWorker 是一个很棒的小设计模式,它允许您这样做(另一种方式是 SwingUtilities)。它对于从外部来源获取数据或进行长时间计算(渲染图形场景)特别有用。它有助于自动调度和随后重新集成来自外部线程(除了 awt 线程)的结果。对于异步事件(即来自 JMS 的事件需要更新结果,请使用 SwingUtilities)。
SwingWorker
使琐碎的示例代码更加简洁。然而,它会产生一个泥球。进出 GUI 和执行逻辑的通信都焊接在一起。所以,我不希望看到它在实际生产代码中使用。
SwingWorker 比处理自己的线程要容易得多,因为它为您提供了两件手动操作很痛苦的事情,UI 和后台进程之间的线程协调以及有效执行循环,后台工作保持工作并将更新逐步发送回 UI,比如处理大量数据,或者加载一个大列表。缺点(或优点)取决于您如何看待它,它隐藏了底层实现,因此未来版本可能具有不同的行为、性能等,这可能是不可取的。我发现它作为 UI 事件和我自己的命令代码之间的粘合剂非常有用,SwingWorker 维护到 UI 的链接并且我的代码泵送数据。