【问题标题】:How to share data with two(2) SwingWorker class in Java如何在 Java 中与两(2)个 SwingWorker 类共享数据
【发布时间】:2023-04-01 07:02:01
【问题描述】:

我有两个 SwingWorker 类:FileLineCounterThreadFileDivisionThread

我将执行这两个线程。当行数计算线程完成后,它会将结果传递给文件分割线程。

我不知道如何将结果传递给已启动的线程。

【问题讨论】:

  • 您确定需要线程来完成 2 个任务吗?在单个 SwingWorker 上连续运行 2 个任务作为方法可能会更简单。
  • @toto:我想知道您的评论是否应该是答案而不是评论,因为在我看来,这是解决原始发布者问题的正确方法。
  • @Hovercraft Full Of Eels 同意,
  • 您能否展示一些代码:两个 SW 是如何启动的,以及两个 SW 方法 doInBackground()done() 是如何执行的(不是完整的代码,而是最有趣的部分)。
  • 希望同时执行以节省等待完成计数的时间。是的,您都是正确的,可以通过一 (1) 个 SwingWorker 类轻松实现它,然后连续运行 2 个任务。我无法发布代码,因为我还不知道如何实现。

标签: java swing concurrency swingworker


【解决方案1】:

PipedReader/Writer 用于字符数据和 PipedInput/OutputStream 用于二进制数据

在 java.io 中。

问候, 斯蒂芬

【讨论】:

    【解决方案2】:

    永远不要举手,永远不要放弃 Executor 和 SwingWorker 的可能性

    1/ Executor and SwingWorker 的错误

    2/ 保持并检查由Executor 和实时SwingWorkers 线程启动的线程数,以避免遇到上述错误

    3/ 检查 Executor 的最大数量或将其限制为最终数量

    根据 OP 的要求更改编辑

    import java.beans.*;
    import java.util.List;
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    import javax.swing.JDialog;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    public class ExecutorAndSwingWorker1 {
    
        private static Executor executor = Executors.newCachedThreadPool();
    
        private static void startButton1() {
            System.out.println("Starting long Tread == startButton1()");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
            }
        }
    
        private static void startButton2() {
            System.out.println("Starting long Tread == startButton2()");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {
            }
        }
    
        private static void startButton3() {
            System.out.println("Starting long Tread == startButton3()");
            try {
                Thread.sleep(1500);
            } catch (InterruptedException ex) {
            }
        }
    
        private static void startButton4() {
            System.out.println("Starting long Tread == startButton4()");
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
            }
        }
    
        private static void endButton1() {
            System.out.println("Long Tread Ends == startButton1()");
            executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton3")); // non on EDT
        }
    
        private static void endButton2() {
            System.out.println("Long Tread Ends == startButton2()");
            executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton4")); // non on EDT
        }
    
        private static void endButton3() {
            System.out.println("Long Tread Ends == startButton3()");
        }
    
        private static void endButton4() {
            System.out.println("Long Tread Ends == startButton3()");
        }
    
        private static 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")) {
                    startButton1();
                } else if (str.equals("startButton2")) {
                    startButton2();
                } else if (str.equals("startButton3")) {
                    startButton3();
                } else if (str.equals("startButton4")) {
                    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 static 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() {
                    executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton1")); // non on EDT
                    executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton2")); // non on EDT
                }
            });
        }
    
        private ExecutorAndSwingWorker1() {
        }
    }
    

    【讨论】:

    • 您能否澄清一下这如何回答 OP 问题? OP 的问题是关于如何将结果从 SW 1 传递到 SW 2?我想这也意味着只有在 SW 1 完成后才应该启动 SW 2,或者至少它的 doInBackground() 应该等待 SW 1 完成......
    • @jfpoilpret 为什么等等,这个例子是关于 Executor 而不是关于 TreadFactory,我会修改它:-)
    • @eros 1) 这是关于编码而不是关于 Java 方法的问题,这段代码是关于只调用内部空隙的基本解决方法,2) 通过一起使用 Executor 和 SwingWorker,3) 并且通过 jfpoilpret 通知我移动了将主方法中的线程拖到私有 void,用于“线程等待另一个线程结束印象”
    • 我很抱歉,但我真的无法理解(可能是由于缺乏知识)。您介意提供直接的答案吗
    • @eros 我再给你发一个例子,还有一些虚构的方法 FileLineCounterThread 和 FileDivisionThread 被翻译成颜色
    【解决方案3】:
    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();
                }
            });
        }
    }
    

    【讨论】:

    • 请至少评论这组代码的关键部分,因为目前它没有用,我正在考虑将其 -1。提前致谢。
    • 很有启发性,虽然有点难以理解。可能用Timer 重构Action?也可以考虑button.setForeground(new Color(random.nextInt() | 0xf0808080, true))setBackground() 在某些 L&F 上是不可见的,例如com.apple.laf.AquaLookAndFeel.
    • @trashgod 对,Timer & Actions 可以包含在一种方法中,但是你碰到了我的问题(我在这里看到的许多程序员的机会),这可能是我无尽的错误,但我在任何情况下都用线性代码编码(长期使用 RPG + Cobol 编码的错误习惯)
    【解决方案4】:

    SwingWorker.execute()buggy 并且只会串行执行任务。使用ExecutorService.execute() 进行并发:

    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.RunnableFuture;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    import javax.swing.WindowConstants;
    
    public class MyFrame extends JFrame implements ActionListener {
    
        /**
         * Test Driver
         */
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    MyFrame frame = new MyFrame("Swing Concurrency Test");
                    frame.setVisible(true);
                }
            });
        }
    
        /**
         * Thread Executor
         * (must be explicitly shutdown, see WindowAdapter below)
         */
        private final ExecutorService exec = Executors.newFixedThreadPool(2);
    
        /**
         * Button action
         */
        @Override
        public void actionPerformed(ActionEvent e) {
            button.setEnabled(false);
            textArea.append("\nStarting both tasks...\n");
    
            // start both tasks, pass a reference to outer task
            FileLineCounterThread counterTask = new FileLineCounterThread();
            exec.execute(counterTask);
            FileDivisionThread divisionTask = new FileDivisionThread(counterTask);
            exec.execute(divisionTask);
        }
    
        /**
         * Counter task
         */
        private class FileLineCounterThread extends SwingWorker<Long, String> {
            private String template = "[FileLineCounterThread] %s\n";
    
            @Override
            protected Long doInBackground() throws Exception {
                // do some work
                publish("started...");
                Thread.sleep(10000);
    
                // return the result
                return 42L;
            }
    
            @Override
            protected void process(List<String> chunks) {
                for (String chunk : chunks) {
                    textArea.append(String.format(template, chunk));
                }
            }
    
            @Override
            protected void done() {
                try {
                    textArea.append(String.format(
                            template, "complete.  Counted: " + get()));
                }
                catch (Exception e) {
                    // catch any exceptions thrown during execution
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * File Division task 
         */
        private class FileDivisionThread extends SwingWorker<String, String> {
            private RunnableFuture<Long> counterTask;
            private String template = "    [FileDivisionThread] %s\n";
    
            public FileDivisionThread(RunnableFuture<Long> counterTask) {
                this.counterTask = counterTask;
            }
    
            @Override
            protected String doInBackground() throws Exception {
                // do some initial work
                publish("started...");
                Thread.sleep(2000);
    
                // wait for other task to complete and get result
                publish("Waiting for line counter to finish...");
                long numLines = counterTask.get(); 
                publish("Line count received: " + numLines);
    
                // do the rest of the work and return result
                Thread.sleep(5000);
                return "complete.";
            }
    
            @Override
            protected void process(List<String> chunks) {
                for (String chunk : chunks) {
                    textArea.append(String.format(template, chunk));
                }
            }
    
            @Override
            protected void done() {
                try {
                    textArea.append(String.format(template, get()));
                    button.setEnabled(true);
                }
                catch (Exception e) {
                    // catch any exceptions thrown during execution
                    e.printStackTrace();
                }
            }
        }
    
        /////////////////////////
        //// GUI Boilerplate ////
        /////////////////////////
    
        private JScrollPane scroller = new JScrollPane();
        private JTextArea textArea = new JTextArea();
        private JButton button = new JButton("Start");
    
        public MyFrame(String windowTitle) {
            super(windowTitle);
            initComponents();
        }
    
        private void initComponents() {
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosed(WindowEvent e) {
                    exec.shutdownNow();
                    System.exit(0);
                }
            });
            button = new JButton("Start");
            button.addActionListener(this);
            textArea = new JTextArea();
            textArea.setColumns(35);
            textArea.setRows(15);
            scroller.setViewportView(textArea);
    
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            getContentPane().setLayout(new GridBagLayout());
    
            GridBagConstraints gridBagConstraints = new GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 0;
            gridBagConstraints.insets = new Insets(10, 0, 0, 0);
            getContentPane().add(button, gridBagConstraints);
    
            gridBagConstraints = new GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 1;
            gridBagConstraints.fill = GridBagConstraints.BOTH;
            gridBagConstraints.weightx = 1.0;
            gridBagConstraints.weighty = 1.0;
            gridBagConstraints.insets = new Insets(10, 10, 10, 10);
            getContentPane().add(scroller, gridBagConstraints);
    
            pack();
        }
    }
    

    【讨论】:

    • then.. ExecutorService.execute() 应该在两次提交后调用?
    • 不,我只是调用了 submit(),但 execute() 实际上会更正确,因为我们不需要 Future 对象(SwingWorker 子类填补了这个角色)。代码更新、测试。
    • +1 表示sscceappend() 在 Java 7 中不再是线程安全的;从process() 调用看起来很安全。也可以考虑setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    【解决方案5】:

    我不确定这是您应该使用的解决方案,它破坏了您从使用 SwingWorker 获得的简单性和安全性,但为了完整起见,我会提到它。

    在两个线程都可以看到它们的地方放置两个字段:一个布尔值,称为hasValue,初始化为false,一个int(或long)称为countValue。两者都必须声明为volatile。当计数器线程完成后,将计数放入countValue然后hasValue 设置为true。然后,除法线程可以定期检查 `hasValue' 并在可用时获取计数。

    如果除法提供的值在获得计数后会更准确,则可以这样做。更有可能的是,它正在做一些工作,然后等待计数。在这种情况下,设置名为countMonitor 的第三个字段,定义为final Object。当它完成初始工作时,让它检查hasValue。如果是真的,抓住价值并继续。如果为 false,请在 countMonitor 上调用 wait 方法并在收到通知时继续。完成后,计数器线程应始终在countMonitor 上调用notifyAll 方法 将值放入hasValuecountValue

    我在这里遗漏了一点。 Object 的 javadoc 将告诉您所需的同步和检查的异常。你的设计很简单,不会被多线程生成的通常的超自然恐怖故事所困扰。我希望。但是如果你走这条路,你可能想做一些研究。 (如果您在同一会话中重复整个过程,您将肯定想做很多研究。)

    【讨论】:

      猜你喜欢
      • 2013-02-25
      • 1970-01-01
      • 1970-01-01
      • 2015-09-08
      • 2012-06-14
      • 2019-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多