Search code examples
javamultithreadingsynchronizationswingworker

How to signal that multiple SwingWorkers are all done?


I have the following issue, or want to do, that I have n running SwingWorkers, the number can vary between 1 and 10. I start them from a main thread, and create them in n numbers, then let them run. After all n SwingWorkers are done, I want to do another task, which basically uses information, the SwingWorkers processed and join them all in the main thread to do something with it. But for this task to begin, all n SwingWorkers need to be finished/done and all n SwingWorkers need to be finished successfully.

What would be the best way to do this? Is there a mechanism in Java already, which does something like this, like a ThreadManager, where you can put multiple SwingWorkers into, and then it fires a doneAll() or something like that to the main thread?

The main thread does other things in the meantime, and cant just wait for the n SwingWorkers to finish. I need an "all done" fire event somehow.

I though of creating another thread in the main thread, which runs a while loop (untillAllSWFfinished), with a wait 500ms in the loop to check, but that seems a bit dirty to me.

Is there a more elegant way to achieve this?


Solution

  • If you know how many workers you're kicking off, you can use a CountdownLatch. If you don't know how many works are being kicked off, you can use a Phaser.

    Example:

    //using a button as a basic UI component to do work.
    JButton button = new JButton(new AbstractAction() {
            
        @Override
        public void actionPerformed(ActionEvent e) {
            Runnable control = new Runnable() {
                @Override
                public void run() {
                    //assuming we know we're going to do 20 bits of isolated work.
                    final CountDownLatch latch = new CountDownLatch(20);
                    for (int i = 0; i < 20; i++) {
                        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
                            @Override
                            public Void doInBackground() {
                                //do your work
                                return null;
                            }
                                
                            @Override
                            public void done() {
                                latch.countDown();
                            }
                        };
                        worker.run()
                    }
                    try {
                       latch.await();
                    } catch (Exception e) {
                       e.printStackTrace();
                    }
                    //so your next bit of work.
                }
            };
            SwingUtilities.invokeLater(control);
        }
    });