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

检测多线程何时完成的正确方法-Java,java,multithreading,Java,Multithreading,我编写了以下方法来并行运行多个线程,当所有线程都完成时,我想触发一些进一步的操作。我已将propertyChangeListener附加到在其自己的线程中运行的每个对象,这些对象中的每个对象在其线程完成时都会触发一个property changed事件。因此,在每一个事件上,我增加一个计数,并将其与对象列表的大小进行比较。一旦它们相等,我就知道所有的线程都完成了。然而,这似乎有点混乱,而且我对多线程非常陌生,所以我想问问其他人对我的方法的看法,以及是否有更优雅或更健壮的方法。谢谢 private

我编写了以下方法来并行运行多个线程,当所有线程都完成时,我想触发一些进一步的操作。我已将propertyChangeListener附加到在其自己的线程中运行的每个对象,这些对象中的每个对象在其线程完成时都会触发一个property changed事件。因此,在每一个事件上,我增加一个计数,并将其与对象列表的大小进行比较。一旦它们相等,我就知道所有的线程都完成了。然而,这似乎有点混乱,而且我对多线程非常陌生,所以我想问问其他人对我的方法的看法,以及是否有更优雅或更健壮的方法。谢谢

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();
            }
        }
    }
private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt){
计数=0;
List specSelList=new ArrayList();
for(字符串str:fileList){
//要运行这些文件吗
如果(!str.equals(“”){
字符串[]args={str};
//运行解决方案
SpeciesSelection specSel=新SpeciesSelection(args,true);
specseList.add(specSel);//将线程添加到列表中,这样我们就可以检查所有要完成的线程。
//创建侦听器以侦听specSel已完成
specSel.addPropertyChangeListener(新的PropertyChangeListener(){
@凌驾
公共作废属性更改(属性更改事件evt){
//做点什么
计数++;
if(count==specSelList.size())
{
System.out.println(“完成所有线程”);
}
}
});
螺纹t=新螺纹(specSel);
t、 start();
}
}
}

您可以像这样使用类
倒计时闩锁

CountDownLatch latch = new CountDownLatch(N);

其中
N
是您启动的线程数。每次线程结束时,您都会传递这个对象并调用
latch.countDown()
。完成所有操作后,闩锁将释放对父线程的控制。

您可以像这样使用类
CountDownLatch

CountDownLatch latch = new CountDownLatch(N);

其中
N
是您启动的线程数。每次线程结束时,您都会传递这个对象并调用
latch.countDown()
。完成所有操作后,闩锁将释放对父线程的控制。

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

CountDownLatch count = new CountDownLatch(nbRequiredCount);
count.await(); 
计数器未设置为
0
时,
wait()
不会返回

并在线程中递减:

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

不要使用
int
计数器并检查其值,而应使用设计为的
CountDownLatch

CountDownLatch count = new CountDownLatch(nbRequiredCount);
count.await(); 
计数器未设置为
0
时,
wait()
不会返回

并在线程中递减:

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

根据给出的建议,我将代码修改如下:

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();
    }
private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt){
List specSelList=new ArrayList();
新线程(){
@凌驾
公开募捐{
试一试{
int numberFiles=fileList.size();
CountDownLatch闩锁=新的CountDownLatch(numberFiles);
for(字符串str:fileList){
//要运行这些文件吗
如果(!str.equals(“”){
字符串[]args={str};
//运行解决方案
SpeciesSelection specSel=新SpeciesSelection(args,true);
specseList.add(specSel);//将线程添加到列表中,这样我们就可以检查所有要完成的线程。
//创建侦听器以侦听specSel已完成
specSel.addPropertyChangeListener(新的PropertyChangeListener(){
@凌驾
公共作废属性更改(属性更改事件evt){
倒计时();
}
});
螺纹t=新螺纹(specSel);
t、 start();
}
}
satch.wait();
System.out.println(“完成所有线程”);
}捕获(中断异常例外){
Logger.getLogger(SpecSelGUI.class.getName()).log(Level.SEVERE,null,ex);
}
}
}.start();
}

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

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

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();
    }
private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt){
List specSelList=new ArrayList();
新线程(){
@凌驾
公开募捐{
试一试{
int numberFiles=fileList.size();
CountDownLatch闩锁=新的CountDownLatch(numberFiles);
for(字符串str:fileList){
//要运行这些文件吗
如果(!str.equals(“”){
字符串[]args={str};
//运行解决方案
SpeciesSelection specSel=新SpeciesSelection(args,true);
specSelList.add(specSel);//将线程添加到列表中以便我们可以检查