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;
    }

}

我希望 csw2 在 csw1 完成后执行,而 csw3 在 csw2 完成后执行。我不希望它们同时执行。我将如何做到这一点?谢谢

4

4 回答 4

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);
    }
  }
}
于 2012-05-01T09:40:35.693 回答
3

您可以使用该get()方法代替execute()- 它会阻塞,直到 SwingWorker 完成其工作。只要确保你没有从 EDT 调用它。

Javadoc 提取:

如有必要,等待计算完成,然后检索其结果。注意:在 Event Dispatch Thread 上调用 get 会阻止处理所有事件,包括重绘,直到此 SwingWorker 完成。

于 2012-04-30T16:18:10.200 回答
3
  • 建议我通过侦听 PropertyChangeListener来查看Executor调用实例SwingWorker

  • 仔细阅读这个帖子,尤其是答案@trashgod

Executor&&& SwingWorker_ PropertyChangeListener_Swing GUI

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

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)
于 2012-04-30T17:53:46.197 回答
2

内存一致性属性对 JLS 进行了总结:“线程中的每个动作都发生在该线程中的每个动作之前,这些动作按程序的顺序出现在后面。” 只需将每个工作人员重新doInBackground()分解为一个单独的方法,然后依次调用每个工作人员:

@Override
protected Void doInBackground() throws Exception {
    doCsw1();
    doCsw2();
    doCsw3();
    return null;
}
于 2012-05-01T00:23:41.433 回答