Java - 依次执行每个SwingWorker类

5

我有多个类继承自SwingWorker。我希望实现的目标是按顺序执行每个类(而不是在前一个类的done方法中执行下一个类)。例如,假设我有:

ClassSwingW1 csw1 = new ClassSwingW1();
csw1.execute;

ClassSwingW2 csw2 = new ClassSwingW2();
csw2.execute;

ClassSwingW3 csw3 = new ClassSwingW3();
csw3.execute;

以及等等。

public class ClassSwingW1 extends SwingWorker<Void, Void> {

    @Override
    protected Void doInBackground() throws Exception {
        //do something

        return null;
    }

}

public class ClassSwingW2 extends SwingWorker<Void, Void> {

    @Override
    protected Void doInBackground() throws Exception {
        //do something

        return null;
    }

}

public class ClassSwingW3 extends SwingWorker<Void, Void> {

    @Override
    protected Void doInBackground() throws Exception {
        //do something

        return null;
    }

}

我希望在csw1执行完后再执行csw2,在csw2完成后再执行csw3,不希望它们同时执行。我该如何实现?谢谢。

2
使用 SwingWorker 的子类是必须的吗?这很重要。 - Radu Murzea
4个回答

3
  • 建议使用Executor调用SwingWorker实例,通过监听PropertyChangeListener来实现。

  • 请仔细阅读此帖子,特别是@trashgod的答案。

ExecutorSwingWorkerPropertyChangeListenerSwing GUI之间的关系如下图所示:

enter image description here

enter image description here

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

public class ExecutorAndSwingWorker2 {

    private JFrame frame = new JFrame();
    private JButton button1;
    private JButton button2;
    private JButton button3;
    private JButton button4;
    private JPanel buttonPanel = new JPanel();
    private Executor executor = Executors.newCachedThreadPool();
    private javax.swing.Timer timer1;
    private javax.swing.Timer timer2;
    private javax.swing.Timer timer3;
    private javax.swing.Timer timer4;
    private Random random = new Random();

    public ExecutorAndSwingWorker2() {
        button1 = new JButton("  Executor + SwingWorker Thread No.1  ");
        button1.setFocusable(false);
        button2 = new JButton("  Executor + SwingWorker Thread No.2  ");
        button3 = new JButton("  Executor + SwingWorker Thread No.3  ");
        button4 = new JButton("  Executor + SwingWorker Thread No.4  ");
        buttonPanel = new JPanel();
        buttonPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
        buttonPanel.setLayout(new GridLayout(2, 2, 20, 20));
        buttonPanel.add(button1);
        buttonPanel.add(button2);
        buttonPanel.add(button3);
        buttonPanel.add(button4);
        frame.setTitle("Shaking Button Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(buttonPanel);
        frame.setPreferredSize(new Dimension(700, 170));
        frame.setLocation(150, 100);
        frame.pack();
        frame.setVisible(true);
        executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton1")); // non on EDT
    }

    private void startButton1() {
        System.out.println("Starting long Thread == startButton1()");
        try {
            Thread.sleep(15000);
        } catch (InterruptedException ex) {
        }
    }

    private void startButton2() {
        System.out.println("Starting long Thread == startButton2()");
        try {
            Thread.sleep(17500);
        } catch (InterruptedException ex) {
        }
    }

    private void startButton3() {
        System.out.println("Starting long Thread == startButton3()");
        try {
            Thread.sleep(12500);
        } catch (InterruptedException ex) {
        }
    }

    private void startButton4() {
        System.out.println("Starting long Thread == startButton4()");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException ex) {
        }
    }

    private void colorAction1() {
        timer1 = new Timer(1000, new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                random = new Random();
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        button1.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
                        button1.validate();
                        button1.repaint();
                    }
                });
            }
        });
        timer1.setDelay(500);
        timer1.setRepeats(true);
        timer1.start();
    }

    private void colorAction2() {
        timer2 = new Timer(1200, new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                random = new Random();
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        button2.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
                        button2.validate();
                        button2.repaint();
                    }
                });
            }
        });
        timer2.setDelay(500);
        timer2.setRepeats(true);
        timer2.start();
    }

    private void colorAction3() {
        timer3 = new Timer(1400, new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                random = new Random();
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        button3.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
                        button3.validate();
                        button3.repaint();
                    }
                });
            }
        });
        timer3.setDelay(500);
        timer3.setRepeats(true);
        timer3.start();
    }

    private void colorAction4() {
        timer4 = new Timer(1600, new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                random = new Random();
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        button4.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
                        button4.validate();
                        button4.repaint();
                    }
                });
            }
        });
        timer4.setDelay(500);
        timer4.setRepeats(true);
        timer4.start();
    }

    private void endButton1() {
        timer1.stop();
        button1.setBackground(null);
        System.out.println("Long Thread Ends == startButton1()");
        executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton3")); // non on EDT
    }

    private void endButton2() {
        timer2.stop();
        button2.setBackground(null);
        System.out.println("Long Thread Ends == startButton2()");
    }

    private void endButton3() {
        timer3.stop();
        button3.setBackground(null);
        System.out.println("Long Thread Ends == startButton3()");
        executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton2")); // non on EDT
        executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton4")); // non on EDT
    }

    private void endButton4() {
        timer4.stop();
        button4.setBackground(null);
        System.out.println("Long Thread Ends == startButton4()");
        executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton1")); // non on EDT
    }

    private class MyTask extends SwingWorker<Void, Integer> {

        private String str;
        private String namePr;
        private JDialog dialog = new JDialog();

        MyTask(String str) {
            this.str = str;
            addPropertyChangeListener(new SwingWorkerCompletionWaiter(dialog, str, namePr));
        }

        @Override
        protected Void doInBackground() throws Exception {
            if (str.equals("startButton1")) {
                colorAction1();
                startButton1();
            } else if (str.equals("startButton2")) {
                colorAction2();
                startButton2();
            } else if (str.equals("startButton3")) {
                colorAction3();
                startButton3();
            } else if (str.equals("startButton4")) {
                colorAction4();
                startButton4();
            }
            return null;
        }

        @Override
        protected void process(List<Integer> progress) {
            System.out.println(str + " " + progress.get(progress.size() - 1));
        }

        @Override
        protected void done() {
            if (str.equals("startButton1")) {
                endButton1();
            } else if (str.equals("startButton2")) {
                endButton2();
            } else if (str.equals("startButton3")) {
                endButton3();
            } else if (str.equals("startButton4")) {
                endButton4();
            }
        }
    }

    private class SwingWorkerCompletionWaiter implements PropertyChangeListener {

        private JDialog dialog;
        private String str;
        private String namePr;

        SwingWorkerCompletionWaiter(JDialog dialog, String str, String namePr) {
            this.dialog = dialog;
            this.str = str;
            this.namePr = namePr;
        }

        @Override
        public void propertyChange(PropertyChangeEvent event) {
            if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) {
                System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) {
                System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) {
                System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else {
                System.out.println("Thread Status with Name :" + str + ", Something wrong happends ");
            }
        }
    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ExecutorAndSwingWorker2 executorAndSwingWorker = new ExecutorAndSwingWorker2();
            }
        });
    }
}

通过 PropertyChangeListener 获得输出

Starting long Thread == startButton1()
Thread Status with Name :startButton1, SwingWorker Status is STARTED
Long Thread Ends == startButton1()
Thread Status with Name :startButton1, SwingWorker Status is DONE
Starting long Thread == startButton3()
Thread Status with Name :startButton3, SwingWorker Status is STARTED
Long Thread Ends == startButton3()
Thread Status with Name :startButton3, SwingWorker Status is DONE
Starting long Thread == startButton2()
Starting long Thread == startButton4()
Thread Status with Name :startButton2, SwingWorker Status is STARTED
Thread Status with Name :startButton4, SwingWorker Status is STARTED
Long Thread Ends == startButton2()
Thread Status with Name :startButton2, SwingWorker Status is DONE
Long Thread Ends == startButton4()
Thread Status with Name :startButton4, SwingWorker Status is DONE
Starting long Thread == startButton1()
Thread Status with Name :startButton1, SwingWorker Status is STARTED
Long Thread Ends == startButton1()
Thread Status with Name :startButton1, SwingWorker Status is DONE
Starting long Thread == startButton3()
Thread Status with Name :startButton3, SwingWorker Status is STARTED
Long Thread Ends == startButton3()
Starting long Thread == startButton2()
Thread Status with Name :startButton3, SwingWorker Status is DONE
Starting long Thread == startButton4()
Thread Status with Name :startButton2, SwingWorker Status is STARTED
Thread Status with Name :startButton4, SwingWorker Status is STARTED
Long Thread Ends == startButton2()
Thread Status with Name :startButton2, SwingWorker Status is DONE
BUILD SUCCESSFUL (total time: 1 minute 34 seconds)

3
如何使用 Executors.newSingleThreadExecutor()
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
import java.util.concurrent.*;
import javax.swing.*;

public class SingleThreadExecutorTest {
  private Executor executor;
  private final Box box = Box.createVerticalBox();
  public JComponent makeUI() {
    executor = Executors.newSingleThreadExecutor(); //.newCachedThreadPool();
    box.setBorder(BorderFactory.createEmptyBorder(8,8,8,8));
    JPanel p = new JPanel(new BorderLayout());
    p.add(new JButton(new AbstractAction("add") {
      @Override public void actionPerformed(ActionEvent evt) {
        doSomethingUseful();
      }
    }), BorderLayout.SOUTH);
    p.add(new JScrollPane(box));
    return p;
  }
  private void doSomethingUseful() {
    JProgressBar bar = new JProgressBar(0, 100);
    box.add(bar); box.add(Box.createVerticalStrut(8));
    box.revalidate();
    SwingWorker<Integer, Void> worker = new SwingWorker<Integer, Void>() {
      private int sleepDummy = new Random().nextInt(50) + 1;
      private int lengthOfTask = 120;
      @Override protected Integer doInBackground() {
        int current = 0;
        while(current<lengthOfTask && !isCancelled()) {
          current++;
          try {
            Thread.sleep(sleepDummy);
          } catch(InterruptedException ie) {
            break;
          }
          setProgress(100 * current / lengthOfTask);
        }
        return sleepDummy*lengthOfTask;
      }
      @Override protected void done() {
        try {
          System.out.println(get()+"ms");
        } catch(Exception ignore) {
          ignore.printStackTrace();
        }
      }
    };
    worker.addPropertyChangeListener(new ProgressListener(bar));
    executor.execute(worker);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new SingleThreadExecutorTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
class ProgressListener implements PropertyChangeListener {
  private final JProgressBar progressBar;
  ProgressListener(JProgressBar progressBar) {
    this.progressBar = progressBar;
    this.progressBar.setValue(0);
  }
  @Override public void propertyChange(PropertyChangeEvent evt) {
    String strPropertyName = evt.getPropertyName();
    if("progress".equals(strPropertyName)) {
      progressBar.setIndeterminate(false);
      int progress = (Integer)evt.getNewValue();
      progressBar.setValue(progress);
    }
  }
}

3
你可以使用 get() 方法 代替 execute(),它将阻塞直到 SwingWorker 完成其工作。只要确保不要从 EDT(Event Dispatch Thread)调用它即可。
Javadoc 提取:
等待必要的计算完成,然后检索其结果。 注意:在事件分派线程上调用 get 会阻止所有事件(包括 repaints)的处理,直到此 SwingWorker 完成为止。

使用get()方法的原因:(https://dev59.com/COo6XIcBkEYKwwoYSClJ) - mKorbel

2

内存一致性属性总结了JLS:“线程中的每个操作都会在程序顺序中后面出现的该线程中的每个操作之前发生。”只需将每个工作线程的doInBackground()方法重构为单独的方法,并按顺序调用每个方法:

@Override
protected Void doInBackground() throws Exception {
    doCsw1();
    doCsw2();
    doCsw3();
    return null;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接