Waiting for multiple SwingWorkers Waiting for multiple SwingWorkers multithreading multithreading

Waiting for multiple SwingWorkers


I intend to remove all of the labels together when all of the workers have completed their tasks.

As described here, a CountDownLatch works well in this context. In the example below, each worker invokes latch.countDown() on completion, and a Supervisor worker blocks on latch.await() until all tasks complete. For demonstration purposes, the Supervisor updates the labels. Wholesale removal, shown in comments, is technically possible but generally unappealing. Instead, consider a JList or JTable.

Worker Latch Test

import java.awt.Color;import java.awt.EventQueue;import java.awt.GridLayout;import java.awt.event.ActionEvent;import java.util.LinkedList;import java.util.List;import java.util.Queue;import java.util.Random;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import javax.swing.*;/*** @see https://stackoverflow.com/a/11372932/230513* @see https://stackoverflow.com/a/3588523/230513*/public class WorkerLatchTest extends JApplet {    private static final int N = 8;    private static final Random rand = new Random();    private Queue<JLabel> labels = new LinkedList<JLabel>();    private JPanel panel = new JPanel(new GridLayout(0, 1));    private JButton startButton = new JButton(new StartAction("Do work"));    public static void main(String[] args) {        EventQueue.invokeLater(new Runnable() {            @Override            public void run() {                JFrame frame = new JFrame();                frame.setTitle("Test");                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                frame.add(new WorkerLatchTest().createGUI());                frame.pack();                frame.setLocationRelativeTo(null);                frame.setVisible(true);            }        });    }    @Override    public void init() {        EventQueue.invokeLater(new Runnable() {            @Override            public void run() {                add(new WorkerLatchTest().createGUI());            }        });    }    private JPanel createGUI() {        for (int i = 0; i < N; i++) {            JLabel label = new JLabel("0", JLabel.CENTER);            label.setOpaque(true);            panel.add(label);            labels.add(label);        }        panel.add(startButton);        return panel;    }    private class StartAction extends AbstractAction {        private StartAction(String name) {            super(name);        }        @Override        public void actionPerformed(ActionEvent e) {                startButton.setEnabled(false);                CountDownLatch latch = new CountDownLatch(N);                ExecutorService executor = Executors.newFixedThreadPool(N);                for (JLabel label : labels) {                    label.setBackground(Color.white);                    executor.execute(new Counter(label, latch));                }                new Supervisor(latch).execute();        }    }    private class Supervisor extends SwingWorker<Void, Void> {        CountDownLatch latch;        public Supervisor(CountDownLatch latch) {            this.latch = latch;        }        @Override        protected Void doInBackground() throws Exception {            latch.await();            return null;        }        @Override        protected void done() {            for (JLabel label : labels) {                label.setText("Fin!");                label.setBackground(Color.lightGray);            }            startButton.setEnabled(true);            //panel.removeAll(); panel.revalidate(); panel.repaint();        }    }    private static class Counter extends SwingWorker<Void, Integer> {        private JLabel label;        CountDownLatch latch;        public Counter(JLabel label, CountDownLatch latch) {            this.label = label;            this.latch = latch;        }        @Override        protected Void doInBackground() throws Exception {            int latency = rand.nextInt(42) + 10;            for (int i = 1; i <= 100; i++) {                publish(i);                Thread.sleep(latency);            }            return null;        }        @Override        protected void process(List<Integer> values) {            label.setText(values.get(values.size() - 1).toString());        }        @Override        protected void done() {            label.setBackground(Color.green);            latch.countDown();        }    }}


The code that you have is already doing that to a certain extent. You need to actually add the label to the contentpane when the button is clicked. Something like this:

 JLabel label = new JLabel(); getContentPane().add(label); getContentPane().validate(); new Worker(label).execute();

It may be a good idea to put some text in the label so you actually see it when it is added to the screen.

 JLabel label = new JLabel("Hello...I am here");

And finally in the doInBackground() method you can add some code to update the label as some task is running:

 for(int i = 0;i < 100; i++){            Thread.sleep(20);            label.setText("Counting..." + i);  }

This way you actually see the task running. If you click the button multiple times you see multiple labels and they each disappear after the task is completed.