| |
实例分析Java SE 6.0新增功能 |
|
时间: 2006-05-23 来自:天极开发 |
 |
|
四、 SwingWorker现在包含到Mustang中
大多数Swing程序员知道,无论什么时候编写事件驱动的代码,例如当一个按钮按下时调用ActionListener,都需要快速处理事件。你永远不需要花费比你必须处理事件驱动的线程更多的时间,否则,你的Swing GUI将成为不可响应并且不能有效地重绘它自己。在事件调度线程中实现一项较大的任务经常意味着你要从事件调度线程中"剔除"一个独立工作者线程并且让该线程运行于后台。这样以来,当使用Swing编写一个多线程的应用程序时,程序员需要牢记下面两条规则:
· 如果把耗时的任务安排到一个调度线程中,那么这有可能导致应用程序具有不可响应性。因此,这样的任务应该用一个工作者线程来专门实现。
· 对Swing组件的更新应该仅安排给一个事件调度线程来完成。
因为这意味着,至少有两个线程在同时运行,因此创建一个处理线程间通讯的类是很有帮助的。有一个消息是,最新的Mustang发行版本中加入了对SwingWorker类(它是前一段时间Swing程序员使用的一种流行的解决方案)的支持。
下面是来自于Javadoc的SwingWorker的正式声明。
public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T> | 注意,这里的声明包含了两个泛型类型变量:T和V。如果你还不熟悉泛型类型变量的话,那么你可以先读一下有关泛型的基础知识,这是在J2SE 5.0中引入的一种特性。下面是定义:
· T:由这个SwingWorker的doInBackground()和get()方法返回的结果类型
· V:被这个SwingWorker的publish()和process()方法用来执行中间结果的类型
一会之后,我们再讨论这些方法。然而,首先,让我们介绍一下SwingWorker中所使用的线程架构。这里援引Javadoc的描述:在一个SwingWorker的生命周期中共包含三个线程:
· 当前线程:execute()方法。它调度SwingWorker在一个工作者线程上的执行并且立即返回。你可以使用两个get()方法之一来等待SwingWorker完成。
· 工作者线程:这个线程上调用doInBackground()方法。这正是所有后台活动发生的地方。为了通知PropertyChangeListeners关于绑定属性的变化,你可以使用firePropertyChange和getPropertyChangeSupport()方法。默认情况下,有两个绑定属性可用-state和progress。
· 事件调度线程:所有的Swing相关的活动都发生在这种线程中。SwingWorker调用process()和done()方法并且通知这个线程上的任何PropertyChangeListeners。
典型地,你在其上实例化SwingWorker子类的当前线程是事件调度线程。这个SwingWorker通常响应下列一些事件:
1. execute()方法被调用或运行于这个事件调度线程上。
2. SwingWorker通知任何PropertyChangeListeners其状态已经变为SwingWorker.StateValue.STARTED。
3. doInBackground()方法在工作者线程上执行。
4. 一旦doInBackground()方法完成,即在当前线程上执行done()方法。
5. SwingWorker通知任何PropertyChangeListeners其状态已经变为SwingWorker.StateValue.DONE。
当在doInBackground()方法中时,你可以设置一个整型的progress属性-它使用下列方法指示工作者线程的当前进度:
| protected void setProgress(int progress); | 一旦调用这个方法,SwingWorker就向所有的已经登记的听者激发一个属性事件来通知它们已经得到更新的进度值。
你可以设置或添加工作者线程的最后结果-通过使用下面两个方法之一:
protected void process(V... chunks); protected void publish(V... chunks); | 第二个方法,publish(),将使用一些中间类型V的一些可变个数的对象并且把它们发送到process()方法中进行处理。典型情况下,你将从doInBackground()线程中调用process()方法。这个process()方法应该总是被重载以接收输入的V参数并且把这些中间对象以某种形式连接成一个T类型。当然,至于process()方法如何实现这一任务要依赖于参数类型-它在你的SwingWorker子类中指定。
同时,在当前线程中,你可以调用两个get()方法之一来检索工作者线程的结果。第一个get()方法,在工作者线程完成其任务之前将会无限地阻塞。第二个方法在检索已经被处理的结果宽之前将阻塞一段指定的时间。
public T get(); public T get(long timeout,TimeUnit unit); | 如果你希望取消这个工作者线程,那么在它完成执行之前,你可以从当前线程中调用cancel()方法。
| public final boolean cancel(boolean mayInterruptIfRunning) | 这里的mayInterruptIfRunning参数指定,在试图停止这项任务时是否执行该任务的线程应该被中断。注意,调用cancel()方法将失败-如果该任务已经完成,如果该任务已经被取消或如果它因某些理由可能无法被取消。然而,如果该方法调用返回true并且当调用cancel()方法时这项任务还没有开始,那么SwingWorker永远不应该执行。
五、 结论
尽管本文中介绍的这些特征基本上相互独立,但是它们的确代表Mustang开发团队希望满足Java开发社区提出的一小部分实现请求。特别是,当创建Swing应用程序时,学习使用SwingWorker类是必须的-它可以把程序员从复杂的GUI线程问题中解脱出来。记住,和往常一样,这些特征在最终成为Java SE 6的最后发行版本之前要征得JSR 270专家组的同意。
|
|
|
|
|
|
|
|