有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程java逐个执行每个SwingWorker类

我有多个扩展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) 个答案

  1. # 1 楼答案

    Memory Consistency Properties总结了JLS:“线程中的每个动作都发生在该线程中的每个动作之前,该线程中的每个动作都是按照程序的顺序进行的。”只需将每个worker的doInBackground()重新分解为一个单独的方法,并按顺序调用每个方法:

    @Override
    protected Void doInBackground() throws Exception {
        doCsw1();
        doCsw2();
        doCsw3();
        return null;
    }
    
  2. # 2 楼答案

    • 建议我查看Executor调用一个SwingWorker实例,从PropertyChangeListener进行监听

    • read carrefully this thread,尤其是@trashgod

    Executor&SwingWorker&PropertyChangeListener&Swing 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. # 3 楼答案

    你可以用^{} method代替execute(),它会一直阻塞,直到SwingWorker完成它的工作。确保你没有从EDT打电话

    Javadoc摘录:

    Waits if necessary for the computation to complete, and then retrieves its result. Note: calling get on the Event Dispatch Thread blocks all events, including repaints, from being processed until this SwingWorker is complete.

  4. # 4 楼答案

    使用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);
        }
      }
    }