Search code examples
javamultithreadingswingswingworker

Execute SwingWorker after another (Synchronize SwingWorker s)


I want to run a SwingWorker after another ends. My 2 threads are inside diferent methods on the same class and I want to use them in order from another class, like this:

int x = runn.runProcessStart();
int y = runn. runProcessEnd();

WORKERS CLASS

public class MyClass {

    private int counter = 0;

    public int runProcessStart() {
        int result = 0;

        SwingWorker<Integer, String> worker = new SwingWorker<Integer, String>() {
            @Override
            protected Integer doInBackground() throws Exception {
                for (int i = 0; i < 10; i++) {
                    publish("start message number " + counter++);
                    Thread.sleep(500);
                }

                return 0;
            }

            @Override
            protected void process(List<String> chunks) {
                // this is called on the Swing event thread
                for (String text : chunks) {
                    Sysem.out.println(text);
                }
            }
        };

        worker.execute();

        if (worker.getState() == SwingWorker.StateValue.DONE) {
            try {
                result = worker.get();
            } catch (ExecutionException | InterruptedException ex) {
                Sysem.out.println(ex.getMEssage());
            }

        }

        return result;
    }

    public int runProcessEnd() {
        int result = 0;

        SwingWorker<Integer, String> worker = new SwingWorker<Integer, String>() {
            @Override
            protected Integer doInBackground() throws Exception {
                for (int i = 0; i < 10; i++) {
                    publish("end message number " + counter++);
                    Thread.sleep(500);
                }

                return 0;
            }

            @Override
            protected void process(List<String> chunks) {
                // this is called on the Swing event thread
                for (String text : chunks) {
                    Sysem.out.println(text);
                }
            }
        };

        worker.execute();

        if (worker.getState() == SwingWorker.StateValue.DONE) {
            try {
                result = worker.get();
            } catch (ExecutionException | InterruptedException ex) {
                Sysem.out.println(ex.getMEssage());
            }

        }

        return result;
    }

}

How can I do this ?

Another question is...is correct the way how I use .get() to retrive value of doInBackground process?


Solution

  • Use SwingWorker#done method as demonstrated in the following mcve:

    import java.awt.BorderLayout;
    import java.util.List;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.SwingWorker;
    
    public class MyClass {
    
        private int counter = 0;
        private JLabel showCounter;
        private JButton start;
    
        public MyClass() {
    
            JFrame window = new JFrame();
            window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            start = new JButton("Start");
            start.addActionListener(e -> runProcessStart());
            window.add(start, BorderLayout.PAGE_START);
    
            showCounter = new JLabel(String.valueOf("Click button to start" ));
            window.add(showCounter, BorderLayout.PAGE_END);
            window.pack();
            window.setVisible(true);
        }
    
        public void runProcessStart() {
    
            start.setEnabled(false);
    
            SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
                @Override
                protected Void doInBackground() throws Exception {
                    for (int i = 0; i < 10; i++) {
                        publish(counter++);
                        Thread.sleep(2000);
                    }
    
                    return null;
                }
    
                @Override
                protected void process(List<Integer> chunks) {
                    for (int i : chunks) {
                        showCounter.setText("Process Start running "+ i);
                    }
                }
    
                @Override
                protected void done() {
                    showCounter.setText("Process Start finished");
                    runProcessEnd();
                }
            };
    
            worker.execute();
        }
    
        public void runProcessEnd() {
    
            SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
                @Override
                protected Void doInBackground() throws Exception {
                    for (int i = 0; i < 10; i++) {
                        Thread.sleep(2000);
                        publish(counter--);
                    }
    
                    return null;
                }
    
                @Override
                protected void process(List<Integer> chunks) {
    
                     for (int i : chunks) {
                         showCounter.setText("Process End running "+ i);
                     }
                }
    
                @Override
                protected void done() {
                    start.setEnabled(true);
                    showCounter.setText("All done");
                }
            };
    
            worker.execute();
        }
    
        public static void main(String[] args) {
            new MyClass();
        }
    }
    

    Note that the values returned by

    int x = runn.runProcessStart();
    int y = runn.runProcessEnd();
    

    in your code, are probably not what you expect, because runProcessStart() and runProcessEnd() return before SwingWorker ends.