简体   繁体   中英

Correct way to detect when multiple threads finished - Java

I wrote the following method to run multiple threads in parallel and when all threads are complete I want to trigger some further action. I've attached a propertyChangeListener to each object that runs in its own thread and each of those objects fires a property changed event when its thread completes. So on each of those events I increment a count and compare it to the size of the list of objects. Once they are equal I know all threads are finished. However, this seems like a bit of a hash up and I'm quite new to multi-threading, so I thought I'd ask what others think of my approach and whether there are more elegant or robust approaches. Thanks.

private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt) {                                                  
        count = 0;
        List<SpeciesSelection> specSelList = new ArrayList<>();

        for (String str : fileList) {
            // TODO RUN THE FILES
            if (!str.equals("")) {
                String[] args = {str};
                //run solution
                SpeciesSelection specSel = new SpeciesSelection(args, true);
                specSelList.add(specSel);// add the thread to the list so we can check for all threads to be finished.

                // Create listener to listen for specSel finished
                specSel.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        // TODO do something
                        count++;
                        if (count == specSelList.size())
                        {
                            System.out.println("Finished all threads");
                        }
                    }
                });

                Thread t = new Thread(specSel);
                t.start();
            }
        }
    }

Rather than using an int counter and check its value use CountDownLatch that is designed to.

CountDownLatch count = new CountDownLatch(nbRequiredCount);
count.await(); 

The await() doesn't return while the counter is not to 0 .

and decrement it in threads :

public void propertyChange(PropertyChangeEvent evt) {
    // TODO do something
    count.countDown();
}

You can use the class CountDownLatch like this:

CountDownLatch latch = new CountDownLatch(N);

where N is the number of threads you launch. You pass around this object and call the latch.countDown() each time a thread finishes. Once they are all done, the latch will release control to the parent thread.

Using the advice given, I altered my code as follows:

private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt) {                                                  
        List<SpeciesSelection> specSelList = new ArrayList<>();
        new Thread() {
            @Override
            public void run() {
                try {
                    int numberFiles = fileList.size();
                    CountDownLatch latch = new CountDownLatch(numberFiles);
                    for (String str : fileList) {
                        // TODO RUN THE FILES
                        if (!str.equals("")) {
                            String[] args = {str};
                            //run solution
                            SpeciesSelection specSel = new SpeciesSelection(args, true);
                            specSelList.add(specSel);// add the thread to the list so we can check for all threads to be finished.

                            // Create listener to listen for specSel finished
                            specSel.addPropertyChangeListener(new PropertyChangeListener() {
                                @Override
                                public void propertyChange(PropertyChangeEvent evt) {
                                    latch.countDown();
                                }
                            });
                            Thread t = new Thread(specSel);
                            t.start();
                        }
                    }
                    latch.await();
                    System.out.println("Finished all threads");
                } catch (InterruptedException ex) {
                    Logger.getLogger(SpecSelGUI.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }.start();
    }

I used the CountDownLatch as suggested but also ran the multiple processes inside an additional anonymous thread so that I could call latch.await() without freezing up the main thread/GUI responsiveness.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM