模块  java.desktop
软件包  javax.swing

Class SwingWorker<T,​V>

  • 参数类型
    T - 此 SwingWorker's doInBackgroundget方法返回的结果类型
    V - 此 SwingWorker's publishprocess方法用于执行中间结果的类型
    实现的所有接口
    RunnableFuture<T>RunnableFuture<T>

    public abstract class SwingWorker<T,​V>
    extends Object
    implements RunnableFuture<T>
    一个抽象类,用于在后台线程中执行冗长的GUI交互任务。 可以使用几个后台线程来执行此类任务。 但是,为任何特定的SwingWorker选择线程的确切策略是未指定的,不应该依赖。

    使用Swing编写多线程应用程序时,请记住以下两个约束:(有关详细信息,请参阅Concurrency in Swing ):

    • 不应在Event Dispatch Thread上运行耗时的任务。 否则应用程序将无响应。
    • 应仅在Event Dispatch Thread上访问Swing组件。

    这些约束意味着具有时间密集型计算的GUI应用程序需要至少两个线程:1)执行冗长任务的线程和2)所有GUI相关活动的事件调度线程 (EDT)。 这涉及线程间通信,这可能很难实现。

    SwingWorker适用于需要在后台线程中运行长时间运行任务并在完成或处理时为UI提供更新的情况。 子类SwingWorker必须实现doInBackground()方法才能执行后台计算。

    工作流程

    SwingWorker的生命周期涉及三个线程:

    • 当前线程:在此线程上调用execute()方法。 它为工作线程执行计划SwingWorker并立即返回。 可以使用get方法等待SwingWorker完成。

    • 工作线程:在此线程上调用doInBackground()方法。 这是所有背景活动应该发生的地方。 要通知PropertyChangeListeners有关绑定属性更改,请使用firePropertyChangegetPropertyChangeSupport()方法。 默认情况下,有两个绑定属性可用: stateprogress

    • 事件调度线程 :此线程上发生所有与Swing相关的活动。 SwingWorker调用processdone()方法并通知此线程上的任何PropertyChangeListeners

    通常, Current线程是Event Dispatch Thread

    工作线程上调用doInBackground方法之前, SwingWorker通知任何PropertyChangeListeners state属性更改为StateValue.STARTED doInBackground方法完成后,执行done方法。 然后SwingWorker通知任何PropertyChangeListeners state属性更改为StateValue.DONE

    SwingWorker仅设计为执行一次。 SwingWorker执行SwingWorker不会导致两次调用doInBackground方法。

    样品使用

    以下示例说明了最简单的用例。 某些处理在后台完成,完成后更新Swing组件。

    假设我们想要找到“生命的意义”并将结果显示在JLabel

      final JLabel label;
       class MeaningOfLifeFinder extends SwingWorker<String, Object> {
           @Override
           public String doInBackground() {
               return findTheMeaningOfLife();
           }
    
           @Override
           protected void done() {
               try {
                   label.setText(get());
               } catch (Exception ignore) {
               }
           }
       }
    
       (new MeaningOfLifeFinder()).execute(); 

    下一个示例在您希望在Event Dispatch Thread上准备好处理数据的情况下非常有用。

    现在我们想要找到前N个素数并在JTextArea显示结果。 虽然这是计算,但我们希望在JProgressBar更新我们的进度。 最后,我们还想将素数打印到System.out

      class PrimeNumbersTask extends
             SwingWorker<List<Integer>, Integer> {
         PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
             //initialize
         }
    
         @Override
         public List<Integer> doInBackground() {
             while (! enough && ! isCancelled()) {
                     number = nextPrimeNumber();
                     publish(number);
                     setProgress(100 * numbers.size() / numbersToFind);
                 }
             }
             return numbers;
         }
    
         @Override
         protected void process(List<Integer> chunks) {
             for (int number : chunks) {
                 textArea.append(number + "\n");
             }
         }
     }
    
     JTextArea textArea = new JTextArea();
     final JProgressBar progressBar = new JProgressBar(0, 100);
     PrimeNumbersTask task = new PrimeNumbersTask(textArea, N);
     task.addPropertyChangeListener(
         new PropertyChangeListener() {
             public  void propertyChange(PropertyChangeEvent evt) {
                 if ("progress".equals(evt.getPropertyName())) {
                     progressBar.setValue((Integer)evt.getNewValue());
                 }
             }
         });
    
     task.execute();
     System.out.println(task.get()); //prints all prime numbers we have got 

    因为SwingWorker实现了RunnableSwingWorker可以将SwingWorker提交到Executor以供执行。

    从以下版本开始:
    1.6
    • 构造方法详细信息

      • SwingWorker

        public SwingWorker()
        构造这个 SwingWorker
    • 方法详细信息

      • doInBackground

        protected abstract T doInBackground()
                                     throws 异常
        计算结果,如果无法执行,则抛出异常。

        请注意,此方法仅执行一次。

        注意:此方法在后台线程中执行。

        结果
        计算结果
        异常
        异常 - 如果无法计算结果
      • publish

        @SafeVarargs
        protected final void publish​(V... chunks)
        将数据块发送到process(java.util.List<V>)方法。 此方法是从里面使用doInBackground方法在里面的事件指派线程提供用于处理中间结果process方法。

        因为process方法是异步调用的事件指派线程多次调用到publish方法之前,可能会出现process执行方法。 出于性能目的,所有这些调用都合并为一个带有连接参数的调用。

        例如:

          publish("1");
         publish("2", "3");
         publish("4", "5", "6"); 
        可能导致:
          process("1", "2", "3", "4", "5", "6") 

        样品使用 此代码段加载一些表格数据并使用它更新DefaultTableModel 请注意,可以安全地从process方法中改变tableModel,因为它是在Event Dispatch Thread上调用的。

          class TableSwingWorker extends
                 SwingWorker<DefaultTableModel, Object[]> {
             private final DefaultTableModel tableModel;
        
             public TableSwingWorker(DefaultTableModel tableModel) {
                 this.tableModel = tableModel;
             }
        
             @Override
             protected DefaultTableModel doInBackground() throws Exception {
                 for (Object[] row = loadData();
                          ! isCancelled() && row != null;
                          row = loadData()) {
                     publish((Object[]) row);
                 }
                 return tableModel;
             }
        
             @Override
             protected void process(List<Object[]> chunks) {
                 for (Object[] row : chunks) {
                     tableModel.addRow(row);
                 }
             }
         } 
        参数
        chunks - 要处理的中间结果
        另请参见:
        process(java.util.List<V>)
      • process

        protected void process​(List<V> chunks)
        事件调度线程上异步接收来自publish方法的数据块。

        有关更多详细信息,请参阅publish(V...)方法。

        参数
        chunks - 要处理的中间结果
        另请参见:
        publish(V...)
      • done

        protected void done()
        doInBackground方法完成后在事件调度线程上执行。 默认实现什么都不做。 子类可以重写此方法以对Event Dispatch Thread执行完成操作。 请注意,您可以在此方法的实现中查询状态,以确定此任务的结果或此任务是否已取消。
        另请参见:
        doInBackground()Future.isCancelled()get()
      • setProgress

        protected final void setProgress​(int progress)
        设置progress绑定属性。 该值应为0到100。

        由于PropertyChangeListener s的在事件指派线程多次调用异步通知setProgress方法可能发生前的任何PropertyChangeListeners被调用。 出于性能目的,所有这些调用仅与最后一个调用参数合并为一个调用。

        例如,以下调用:

          setProgress(1);
         setProgress(2);
         setProgress(3); 
        可能会导致单个PropertyChangeListener通知,其值为3
        参数
        progress - 要设置的进度值
        异常
        IllegalArgumentException - 值不是0到100
      • getProgress

        public final int getProgress()
        返回 progress绑定属性。
        结果
        进度约束属性。
      • execute

        public final void execute()
        安排此SwingWorker工作线程上执行。 有许多工作线程可用。 如果所有工作线程都忙于处理其他SwingWorkersSwingWorker被置于等待队列中。

        注意: SwingWorker仅设计为执行一次。 SwingWorker执行SwingWorker不会导致两次调用doInBackground方法。

      • get

        public final T get()
                    throws InterruptedException,
                           ExecutionException
        如果需要等待计算完成,然后检索其结果。

        注意:在事件调度线程上调用get阻止所有事件(包括重新绘制)被处理,直到此SwingWorker完成。

        如果希望SwingWorker阻止事件调度线程,我们建议您使用模式对话框

        例如:

          class SwingWorkerCompletionWaiter implements PropertyChangeListener {
             private JDialog dialog;
        
             public SwingWorkerCompletionWaiter(JDialog dialog) {
                 this.dialog = dialog;
             }
        
             public void propertyChange(PropertyChangeEvent event) {
                 if ("state".equals(event.getPropertyName())
                         && SwingWorker.StateValue.DONE == event.getNewValue()) {
                     dialog.setVisible(false);
                     dialog.dispose();
                 }
             }
         }
         JDialog dialog = new JDialog(owner, true);
         swingWorker.addPropertyChangeListener(
             new SwingWorkerCompletionWaiter(dialog));
         swingWorker.execute();
         //the dialog will be visible until the SwingWorker is done
         dialog.setVisible(true); 
        Specified by:
        get接口 Future<T>
        结果
        计算结果
        异常
        CancellationException - 如果计算被取消
        InterruptedException - 如果当前线程在等待时被中断
        ExecutionException - 如果计算引发异常
      • addPropertyChangeListener

        public final void addPropertyChangeListener​(PropertyChangeListener listener)
        PropertyChangeListener添加到侦听器列表中。 监听器已注册所有属性。 可以多次添加相同的侦听器对象,并且在添加时将多次调用它。 如果listenernull ,则不会抛出任何异常并且不执行任何操作。

        注意:这只是一个方便的包装器。 所有工作PropertyChangeSupport getPropertyChangeSupport()委托给PropertyChangeSupport

        参数
        listener - 要添加的 PropertyChangeListener
      • removePropertyChangeListener

        public final void removePropertyChangeListener​(PropertyChangeListener listener)
        从侦听器列表中删除PropertyChangeListener 这将删除为所有属性注册的PropertyChangeListener 如果listenerlistener添加到同一事件源,则会在删除后将其通知一次。 如果listenernull ,或者从未添加过,则不会抛出任何异常并且不执行任何操作。

        注意:这只是一个方便的包装器。 所有工作PropertyChangeSupport getPropertyChangeSupport()委托给PropertyChangeSupport

        参数
        listener - 要删除的 PropertyChangeListener
      • firePropertyChange

        public final void firePropertyChange​(String propertyName,
                                             Object oldValue,
                                             Object newValue)
        向任何已注册的侦听器报告绑定属性更新。 如果oldnew相等且非空,则old触发任何事件。

        SwingWorker将是任何生成的事件的源。

        如果取消了事件指派线程 PropertyChangeListeners都在事件指派线程上异步地通知。

        注意:这只是一个方便的包装器。 所有工作PropertyChangeSupport getPropertyChangeSupport()委托给PropertyChangeSupport

        参数
        propertyName - 已更改的属性的编程名称
        oldValue - 属性的旧值
        newValue - 该属性的新值
      • getPropertyChangeSupport

        public final PropertyChangeSupport getPropertyChangeSupport()
        返回PropertyChangeSupportSwingWorker 当需要灵活访问绑定属性支持时,使用此方法。

        SwingWorker将成为任何生成事件的源。

        注:返回PropertyChangeSupport通知任何PropertyChangeListener小号异步对事件的事件调度线程 firePropertyChangefireIndexedPropertyChange被叫停事件指派线程

        结果
        PropertyChangeSupport这个 SwingWorker
      • getState

        public final SwingWorker.StateValue getState()
        返回 SwingWorker状态绑定属性。
        结果
        目前的状态