[java] 여러 스레드가 완료 될 때까지 기다리는 방법은 무엇입니까?

모든 스레드 프로세스가 완료 될 때까지 기다리는 방법은 무엇입니까? 예를 들어 다음과 같이 가정 해 보겠습니다.

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
    }


}

main()모든 스레드의 run()메서드가 종료 될 때까지 메서드가 주석에서 일시 중지 되도록 어떻게 변경 합니까? 감사!



답변

모든 스레드를 배열에 넣고 모두 시작한 다음 루프가 있습니다.

for(i = 0; i < threads.length; i++)
  threads[i].join();

각 조인은 해당 스레드가 완료 될 때까지 차단됩니다. 스레드는 결합하는 순서와 다른 순서로 완료 될 수 있지만 문제는 아닙니다. 루프가 종료되면 모든 스레드가 완료됩니다.


답변

한 가지 방법은 수 있도록하는 것입니다 ListThread목록에 추가하는 동안, S 만들고 각 스레드를 실행합니다. 모든 것이 시작되면 목록을 반복 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

ExecutorService (및 Java 5 동시성 유틸리티 의 모든 새로운 기능 )를 사용하는 것은 매우 유연하며 위의 예는 표면을 거의 긁지 않습니다.


답변

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
   }
}


답변

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

설명 :

  1. CountDownLatch 귀하의 요구 사항에 따라 주어진 카운트 1000으로 초기화되었습니다.

  2. 각 작업자 스레드 DoSomethingInAThreadCountDownLatch생성자에 전달 된를 감소시킵니다 .

  3. CountDownLatchDemo await()카운트가 0이 될 때까지 메인 스레드 . 카운트가 0이되면 출력에서 ​​줄 아래에있게됩니다.

    In Main thread after completion of 1000 threads

오라클 문서 페이지에서 더 많은 정보

public void await()
           throws InterruptedException

스레드가 인터럽트되지 않는 한 현재 스레드가 래치가 0이 될 때까지 대기하도록합니다.

다른 옵션은 관련 SE 질문을 참조하십시오.

모든 스레드가 Java에서 작업을 마칠 때까지 기다립니다.


답변

Thread 클래스를 아예 피하고 대신 java.util.concurrent에서 제공하는 더 높은 추상화를 사용하십시오.

ExecutorService 클래스는 원하는 작업을 수행하는 것 같은 invokeAll 메소드를 제공합니다 .


답변

사용하는 것이 좋습니다 java.util.concurrent.CountDownLatch. javadocs의


답변

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

}