Module  java.desktop
软件包  javax.swing

Class SwingWorker<T,V>

  • 参数类型
    T - 该 SwingWorker's doInBackgroundget方法返回的结果类型
    V - 用于执行中间结果的类型 SwingWorker's publishprocess方法
    All Implemented Interfaces:
    RunnableFuture<T>RunnableFuture<T>


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

    当使用Swing编写多线程应用程序时,请注意以下两个限制:(有关详细信息,请参阅Concurrency in Swing ):

    • 事件调度线程不应该运行耗时的任务。 否则应用程序将无响应。
    • 只能在事件分派线程上访问Swing组件。

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

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

    工作流程

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

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

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

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

    通常, 当前线程是事件调度线程

    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(); 

    下一个示例在您希望在事件分派线程上准备好处理数据的情况下很有用。

    现在我们要找到前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实现Runnable ,一个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方法在事件分派线程上异步调用,因此在执行process方法之前可能会发生多次调用到publish方法。 为了表现目的,所有这些调用都合并成一个带有连接参数的调用。

        例如:

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

        样品用法 此代码段加载了一些表格数据和更新DefaultTableModel 请注意,由于在事件分派线程中调用了,因此可以安全地从process方法中process

          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方法后,在事件发送 doInBackground执行。 默认实现什么都不做。 子类可以覆盖此方法以在事件分派线程上执行完成操作。 请注意,您可以在该方法的实现中查询状态,以确定此任务的结果或此任务是否已被取消。
        另请参见:
        doInBackground()isCancelled()get()
      • setProgress

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

        因为PropertyChangeListener事件调度线程上被异步通知,因此在调用任何PropertyChangeListeners之前,可能会发生多项到setProgress方法的调用。 为了执行目的,所有这些调用都合并到一个调用中,最后一个调用参数。

        例如,以下调用:

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

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

        public final void execute​()
        计划这个SwingWorker用于在工作线程上执行。 有多个工作线程可用。 在所有工作线程正忙于处理其他SwingWorkers情况下, SwingWorker被放置在等待队列中。

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

      • cancel

        public final boolean cancel​(boolean mayInterruptIfRunning)
        尝试取消执行此任务。 如果任务已经完成,已经被取消或由于某种其他原因而无法取消,则此尝试将失败。 如果成功,并且当cancel时此任务尚未启动,则此任务不应运行。 如果任务已经开始,那么mayInterruptIfRunning参数确定执行此任务的线程是否应该中断,以试图停止任务。

        此方法返回后,后续调用Future.isDone()将始终返回true 对后续调用Future.isCancelled()总是返回true如果此方法返回true

        Specified by:
        cancel在接口 Future<T>
        参数
        mayInterruptIfRunning - true如果执行该任务的线程应该被中断; 否则,正在进行的任务被允许完成
        结果
        false如果任务无法取消,通常是因为它已经正常完成; 否则为true
      • isCancelled

        public final boolean isCancelled​()
        如果此任务在正常完成之前被取消,则返回 true
        Specified by:
        isCancelled在接口 Future<T>
        结果
        true如果此任务在完成之前被取消
      • isDone

        public final boolean isDone​()
        如果此任务完成,则返回true 完成可能是由于正常终止,异常或取消 - 在所有这些情况下,此方法将返回true
        Specified by:
        isDone在接口 Future<T>
        结果
        true如果这个任务完成了
      • 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>
        结果
        计算结果
        异常
        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 如果listener添加到同一个事件源,则被删除后将被通知一次。 如果listenernull ,或者从未添加过,则不会抛出异常并且不采取任何操作。

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

        参数
        listener - 要删除的 PropertyChangeListener
      • firePropertyChange

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

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

        当调用事件调度线程 PropertyChangeListeners被异步通知事件分派线程时

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

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

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

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

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

        结果
        PropertyChangeSupport为这 SwingWorker
      • getState

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