如何等待多个线程完成?

Div*_*ero 103 java parallel-processing multithreading wait

简单地等待所有线程进程完成的方法是什么?例如,假设我有:

public class DoSomethingInAThread implements Runnable{

    public static void main(String[] args) {
        for (int n=0; n<1000; n++) {
            Thread t = new Thread(new DoSomethingInAThread());
            t.start();
        }
        // wait for all threads' run() methods to complete before continuing
    }

    public void run() {
        // do something here
    }


}
Run Code Online (Sandbox Code Playgroud)

我如何改变这一点,以便main()方法在注释处暂停,直到所有线程的run()方法都退出?谢谢!

Mar*_*wis 157

您将所有线程放在一个数组中,启动它们,然后循环

for(i = 0; i < threads.length; i++)
  threads[i].join();
Run Code Online (Sandbox Code Playgroud)

每个连接将阻塞,直到相应的线程完成.线程可以以与加入它们不同的顺序完成,但这不是问题:当循环退出时,所有线程都完成.

  • 自Java 5以来,线程组是更自然的方式. (13认同)
  • ThreadGroup没有实现组级连接,所以人们为什么推动ThreadGroup有点莫名其妙.人们真的使用自旋锁并查询该组的activeCount吗?与仅在所有线程上调用join相比,你很难说服我这样做更好. (5认同)
  • "Effective Java"一书建议避免使用线程组(第73项). (4认同)
  • 请参阅:"线程组表示一组线程." 对于这个用例,这是语义正确的!并且:"允许线程访问有关其自己的线程组的信息" (2认同)
  • Effective Java中提到的错误应该已在Java 6中修复.如果较新的java版本不是限制,最好使用Futures来解决线程问题.Martinv.Löwis:你是对的.它并不是对这个问题的反应,但是从一个Object(比如ExecutorService)获取有关正在运行的线程的更多信息是很好的.我认为使用给定的功能来解决问题是很好的; 也许你将来需要更多的灵活性(线程信息).在较旧的JDK中提及旧的错误类也是正确的. (2认同)

Ada*_*kin 37

一种方法是做一个ListThreadS,创建和启动每个线程,而将其添加到列表中.一旦启动所有内容,循环回列表并调用join()每个列表.线程完成执行的顺序并不重要,您需要知道的是,当第二个循环完成执行时,每个线程都将完成.

更好的方法是使用ExecutorService及其相关方法:

List<Callable> callables = ... // assemble list of Callables here
                               // Like Runnable but can return a value
ExecutorService execSvc = Executors.newCachedThreadPool();
List<Future<?>> results = execSvc.invokeAll(callables);
// Note: You may not care about the return values, in which case don't
//       bother saving them
Run Code Online (Sandbox Code Playgroud)

使用ExecutorService(以及来自Java 5的并发实用程序的所有新东西)非常灵活,上面的示例几乎没有表面上的划痕.

  • 什么?你怎么会遇到麻烦?它只是在执行启动的线程中可变(只能读取),所以只要它不会修改列表*而*迭代它,它就没问题了. (3认同)

jt.*_*jt. 24

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class DoSomethingInAThread implements Runnable
{
   public static void main(String[] args) throws ExecutionException, InterruptedException
   {
      //limit the number of actual threads
      int poolSize = 10;
      ExecutorService service = Executors.newFixedThreadPool(poolSize);
      List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();

      for (int n = 0; n < 1000; n++)
      {
         Future f = service.submit(new DoSomethingInAThread());
         futures.add(f);
      }

      // wait for all tasks to complete before continuing
      for (Future<Runnable> f : futures)
      {
         f.get();
      }

      //shut down the executor service so that this thread can exit
      service.shutdownNow();
   }

   public void run()
   {
      // do something here
   }
}
Run Code Online (Sandbox Code Playgroud)


Rav*_*abu 9

而不是join()旧的API,您可以使用CountDownLatch.我已经修改了您的代码,以满足您的要求.

import java.util.concurrent.*;
class DoSomethingInAThread implements Runnable{
    CountDownLatch latch;
    public DoSomethingInAThread(CountDownLatch latch){
        this.latch = latch;
    } 
    public void run() {
        try{
            System.out.println("Do some thing");
            latch.countDown();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

public class CountDownLatchDemo {
    public static void main(String[] args) {
        try{
            CountDownLatch latch = new CountDownLatch(1000);
            for (int n=0; n<1000; n++) {
                Thread t = new Thread(new DoSomethingInAThread(latch));
                t.start();
            }
            latch.await();
            System.out.println("In Main thread after completion of 1000 threads");
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

说明:

  1. CountDownLatch 已根据您的要求初始化给定计数1000.

  2. 每个工作线程DoSomethingInAThread 将递减CountDownLatch,它已在构造函数中传递.

  3. 主线程CountDownLatchDemo await()直到计数变为零.一旦计数变为零,您将获得输出线以下.

    In Main thread after completion of 1000 threads
    
    Run Code Online (Sandbox Code Playgroud)

更多信息来自oracle文档页面

public void await()
           throws InterruptedException
Run Code Online (Sandbox Code Playgroud)

除非线程被中断,否则导致当前线程等待锁存器倒计数到零.

有关其他选项,请参阅相关的SE问题:

等到所有线程完成他们在java中的工作


小智 8

完全避免使用Thread类,而是使用java.util.concurrent中提供的更高抽象

ExecutorService类提供的方法invokeAll似乎只是你想要的.


Jef*_*eff 6

根据您的需要,您可能还想查看 java.util.concurrent 包中的 CountDownLatch 和 CyclicBarrier 类。如果您希望线程相互等待,或者希望对线程执行方式进行更细粒度的控制(例如,在其内部执行中等待另一个线程设置某种状态),那么它们会很有用。您还可以使用 CountDownLatch 向所有线程发出同时启动的信号,而不是在迭代循环时逐个启动它们。标准 API 文档有一个这样的示例,并使用另一个 CountDownLatch 来等待所有线程完成执行。


小智 6

考虑使用java.util.concurrent.CountDownLatch. javadoc 中的示例


Fre*_*mmi 6

正如Martin K所说, java.util.concurrent.CountDownLatch似乎是一个更好的解决方案.只需添加相同的示例

     public class CountDownLatchDemo
{

    public static void main (String[] args)
    {
        int noOfThreads = 5;
        // Declare the count down latch based on the number of threads you need
        // to wait on
        final CountDownLatch executionCompleted = new CountDownLatch(noOfThreads);
        for (int i = 0; i < noOfThreads; i++)
        {
            new Thread()
            {

                @Override
                public void run ()
                {

                    System.out.println("I am executed by :" + Thread.currentThread().getName());
                    try
                    {
                        // Dummy sleep
                        Thread.sleep(3000);
                        // One thread has completed its job
                        executionCompleted.countDown();
                    }
                    catch (InterruptedException e)
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            }.start();
        }

        try
        {
            // Wait till the count down latch opens.In the given case till five
            // times countDown method is invoked
            executionCompleted.await();
            System.out.println("All over");
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)