检测多个线程何时完成的正确方法 - Java

时间:2018-02-28 11:56:44

标签: java multithreading

我编写了以下方法来并行运行多个线程,当所有线程都完成时,我想触发一些进一步的操作。我已将propertyChangeListener附加到在其自己的线程中运行的每个对象,并且每个对象在其线程完成时触发属性更改事件。因此,在每个事件中,我增加一个计数并将其与对象列表的大小进行比较。一旦它们相等,我知道所有线程都已完成。然而,这看起来有点像哈希,我对多线程很陌生,所以我想我会问别人对我的方法的看法,以及是否有更优雅或更强大的方法。感谢。

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();
            }
        }
    }

3 个答案:

答案 0 :(得分:2)

而不是使用int计数器并检查其值,使用专为此设计的CountDownLatch

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

await()在计数器不到0时不会返回。

并在线程中减少它:

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

答案 1 :(得分:0)

您可以像这样使用课程CountDownLatch

CountDownLatch latch = new CountDownLatch(N);

其中N是您启动的线程数。您传递此对象并在每次线程完成时调用latch.countDown()。一旦完成,锁存器将释放对父线程的控制。

答案 2 :(得分:0)

使用给出的建议,我改变了我的代码如下:

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();
    }

我按照建议使用了CountDownLatch,但是在一个额外的匿名线程中运行了多个进程,这样我就可以调用latch.await()而不会冻结主线程/ GUI响应。