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

前端 未结 26 1867
你的背包
你的背包 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:29
    
    ExecutorService WORKER_THREAD_POOL 
      = Executors.newFixedThreadPool(10);
    CountDownLatch latch = new CountDownLatch(2);
    for (int i = 0; i < 2; i++) {
        WORKER_THREAD_POOL.submit(() -> {
            try {
                // doSomething();
                latch.countDown();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
    }
    
    // wait for the latch to be decremented by the two remaining threads
    latch.await();
    

    If doSomething() throw some other exceptions, the latch.countDown() seems will not execute, so what should I do?

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

    This might help

    Log.i(LOG_TAG, "shutting down executor...");
    executor.shutdown();
    while (true) {
                    try {
                        Log.i(LOG_TAG, "Waiting for executor to terminate...");
                        if (executor.isTerminated())
                            break;
                        if (executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
                            break;
                        }
                    } catch (InterruptedException ignored) {}
                }
    
    0 讨论(0)
  • 2020-11-22 02:32

    A bit late to the game but for the sake of completion...

    Instead of 'waiting' for all tasks to finish, you can think in terms of the Hollywood principle, "don't call me, I'll call you" - when I'm finished. I think the resulting code is more elegant...

    Guava offers some interesting tools to accomplish this.

    An example ::

    Wrap an ExecutorService into a ListeningExecutorService ::

    ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
    

    Submit a collection of callables for execution ::

    for (Callable<Integer> callable : callables) {
      ListenableFuture<Integer> lf = service.submit(callable);
      // listenableFutures is a collection
      listenableFutures.add(lf)
    });
    

    Now the essential part:

    ListenableFuture<List<Integer>> lf = Futures.successfulAsList(listenableFutures);
    

    Attach a callback to the ListenableFuture, that you can use to be notified when all futures complete ::

            Futures.addCallback(lf, new FutureCallback<List<Integer>>() {
            @Override
            public void onSuccess(List<Integer> result) {
                log.info("@@ finished processing {} elements", Iterables.size(result));
                // do something with all the results
            }
    
            @Override
            public void onFailure(Throwable t) {
                log.info("@@ failed because of :: {}", t);
            }
        });
    

    This also offers the advantage that you can collect all the results in one place once the processing is finished...

    More information here

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

    you should use executorService.shutdown() and executorService.awaitTermination method.

    An example as follows :

    public class ScheduledThreadPoolExample {
    
        public static void main(String[] args) throws InterruptedException {
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
            executorService.scheduleAtFixedRate(() -> System.out.println("process task."),
                    0, 1, TimeUnit.SECONDS);
    
            TimeUnit.SECONDS.sleep(10);
            executorService.shutdown();
            executorService.awaitTermination(1, TimeUnit.DAYS);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-22 02:32

    Clean way with ExecutorService

     List<Future<Void>> results = null;
     try {
         List<Callable<Void>> tasks = new ArrayList<>();
         ExecutorService executorService = Executors.newFixedThreadPool(4);
         results = executorService.invokeAll(tasks);
     } catch (InterruptedException ex) {
         ...
     } catch (Exception ex) {
         ...
     }
    
    0 讨论(0)
  • 2020-11-22 02:33

    Just my two cents. To overcome the requirement of CountDownLatch to know the number of tasks beforehand, you could do it the old fashion way by using a simple Semaphore.

    ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
    int numberOfTasks=0;
    Semaphore s=new Semaphore(0);
    while(...) {
        taskExecutor.execute(new MyTask());
        numberOfTasks++;
    }
    
    try {
        s.aquire(numberOfTasks);
    ...
    

    In your task just call s.release() as you would latch.countDown();

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