How to wait for all threads to finish, using ExecutorService?

前端 未结 26 2000
你的背包
你的背包 2020-11-22 01:55

I need to execute some amount of tasks 4 at a time, something like this:

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
    tas         


        
相关标签:
26条回答
  • 2020-11-22 02:46

    You could use this code:

    public class MyTask implements Runnable {
    
        private CountDownLatch countDownLatch;
    
        public MyTask(CountDownLatch countDownLatch {
             this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
             try {
                 //Do somethings
                 //
                 this.countDownLatch.countDown();//important
             } catch (InterruptedException ex) {
                  Thread.currentThread().interrupt();
             }
         }
    }
    
    CountDownLatch countDownLatch = new CountDownLatch(NUMBER_OF_TASKS);
    ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
    for (int i = 0; i < NUMBER_OF_TASKS; i++){
         taskExecutor.execute(new MyTask(countDownLatch));
    }
    countDownLatch.await();
    System.out.println("Finish tasks");
    
    0 讨论(0)
  • 2020-11-22 02:47

    if you use more thread ExecutionServices SEQUENTIALLY and want to wait EACH EXECUTIONSERVICE to be finished. The best way is like below;

    ExecutorService executer1 = Executors.newFixedThreadPool(THREAD_SIZE1);
    for (<loop>) {
       executer1.execute(new Runnable() {
                @Override
                public void run() {
                    ...
                }
            });
    } 
    executer1.shutdown();
    
    try{
       executer1.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    
       ExecutorService executer2 = Executors.newFixedThreadPool(THREAD_SIZE2);
       for (true) {
          executer2.execute(new Runnable() {
                @Override
                public void run() {
                     ...
                }
            });
       } 
       executer2.shutdown();
    } catch (Exception e){
     ...
    }
    
    0 讨论(0)
  • 2020-11-22 02:48

    Basically on an ExecutorService you call shutdown() and then awaitTermination():

    ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
    while(...) {
      taskExecutor.execute(new MyTask());
    }
    taskExecutor.shutdown();
    try {
      taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
      ...
    }
    
    0 讨论(0)
  • 2020-11-22 02:53

    The CyclicBarrier class in Java 5 and later is designed for this sort of thing.

    0 讨论(0)
  • 2020-11-22 02:54

    Just to provide more alternatives here different to use latch/barriers. You can also get the partial results until all of them finish using CompletionService.

    From Java Concurrency in practice: "If you have a batch of computations to submit to an Executor and you want to retrieve their results as they become available, you could retain the Future associated with each task and repeatedly poll for completion by calling get with a timeout of zero. This is possible, but tedious. Fortunately there is a better way: a completion service."

    Here the implementation

    public class TaskSubmiter {
        private final ExecutorService executor;
        TaskSubmiter(ExecutorService executor) { this.executor = executor; }
        void doSomethingLarge(AnySourceClass source) {
            final List<InterestedResult> info = doPartialAsyncProcess(source);
            CompletionService<PartialResult> completionService = new ExecutorCompletionService<PartialResult>(executor);
            for (final InterestedResult interestedResultItem : info)
                completionService.submit(new Callable<PartialResult>() {
                    public PartialResult call() {
                        return InterestedResult.doAnOperationToGetPartialResult();
                    }
            });
    
        try {
            for (int t = 0, n = info.size(); t < n; t++) {
                Future<PartialResult> f = completionService.take();
                PartialResult PartialResult = f.get();
                processThisSegment(PartialResult);
                }
            } 
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } 
            catch (ExecutionException e) {
                throw somethinghrowable(e.getCause());
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:54

    I created the following working example. The idea is to have a way to process a pool of tasks (I am using a queue as example) with many Threads (determined programmatically by the numberOfTasks/threshold), and wait until all Threads are completed to continue with some other processing.

    import java.util.PriorityQueue;
    import java.util.Queue;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /** Testing CountDownLatch and ExecutorService to manage scenario where
     * multiple Threads work together to complete tasks from a single
     * resource provider, so the processing can be faster. */
    public class ThreadCountDown {
    
    private CountDownLatch threadsCountdown = null;
    private static Queue<Integer> tasks = new PriorityQueue<>();
    
    public static void main(String[] args) {
        // Create a queue with "Tasks"
        int numberOfTasks = 2000;
        while(numberOfTasks-- > 0) {
            tasks.add(numberOfTasks);
        }
    
        // Initiate Processing of Tasks
        ThreadCountDown main = new ThreadCountDown();
        main.process(tasks);
    }
    
    /* Receiving the Tasks to process, and creating multiple Threads
    * to process in parallel. */
    private void process(Queue<Integer> tasks) {
        int numberOfThreads = getNumberOfThreadsRequired(tasks.size());
        threadsCountdown = new CountDownLatch(numberOfThreads);
        ExecutorService threadExecutor = Executors.newFixedThreadPool(numberOfThreads);
    
        //Initialize each Thread
        while(numberOfThreads-- > 0) {
            System.out.println("Initializing Thread: "+numberOfThreads);
            threadExecutor.execute(new MyThread("Thread "+numberOfThreads));
        }
    
        try {
            //Shutdown the Executor, so it cannot receive more Threads.
            threadExecutor.shutdown();
            threadsCountdown.await();
            System.out.println("ALL THREADS COMPLETED!");
            //continue With Some Other Process Here
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
    
    /* Determine the number of Threads to create */
    private int getNumberOfThreadsRequired(int size) {
        int threshold = 100;
        int threads = size / threshold;
        if( size > (threads*threshold) ){
            threads++;
        }
        return threads;
    }
    
    /* Task Provider. All Threads will get their task from here */
    private synchronized static Integer getTask(){
        return tasks.poll();
    }
    
    /* The Threads will get Tasks and process them, while still available.
    * When no more tasks available, the thread will complete and reduce the threadsCountdown */
    private class MyThread implements Runnable {
    
        private String threadName;
    
        protected MyThread(String threadName) {
            super();
            this.threadName = threadName;
        }
    
        @Override
        public void run() {
            Integer task;
            try{
                //Check in the Task pool if anything pending to process
                while( (task = getTask()) != null ){
                    processTask(task);
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }finally {
                /*Reduce count when no more tasks to process. Eventually all
                Threads will end-up here, reducing the count to 0, allowing
                the flow to continue after threadsCountdown.await(); */
                threadsCountdown.countDown();
            }
        }
    
        private void processTask(Integer task){
            try{
                System.out.println(this.threadName+" is Working on Task: "+ task);
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }
    }
    

    Hope it helps!

    0 讨论(0)
提交回复
热议问题