Як дочекатися завершення всіх потоків за допомогою ExecutorService?


381

Мені потрібно виконати деяку кількість завдань 4, одночасно:

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
    taskExecutor.execute(new MyTask());
}
//...wait for completion somehow

Як я можу отримати повідомлення, коли всі вони завершені? Поки що я не можу думати ні про що краще, ніж встановити якийсь глобальний лічильник завдань і зменшити його в кінці кожного завдання, а потім стежити за нескінченним циклом цього лічильника на 0; або отримати список ф'ючерсів і в нескінченному циклі монітора isDone для всіх них. Які кращі рішення не включають нескінченні петлі?

Дякую.

Відповіді:


446

В основному на ExecutorServiceдзвінок, shutdown()а потім awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

9
саме для цього покликане завершення роботи / очікування випробування
мат b

31
Це хороший зразок, якщо вирішення цього завдання є одноразовою подією. Якщо це робиться неодноразово протягом одного і того ж періоду виконання, це не є оптимальним, оскільки ви б створювали та зривали нитки повторно кожного разу, коли воно виконується.
sjlee

44
Я шукаю будь-яку офіційну документацію, яка Long.MAX_VALUE, TimeUnit.NANOSECONDSеквівалентна відсутності тайм-ауту.
Сем Харвелл

15
Я не можу повірити, що вам потрібно використовувати shutdown для того, щоб приєднатись до всіх поточних потоків (після використання shutdown ви не можете знову використовувати виконавця). Запропонуйте скористатися списком Future's замість ...
rogerdpack

20
@SamHarwell дивіться java.util.concurrentпакетну документацію в Timingрозділі: Щоб чекати "назавжди", ви можете використовувати значенняLong.MAX_VALUE
beluchin

174

Використовуйте CountDownLatch :

CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}

try {
  latch.await();
} catch (InterruptedException E) {
   // handle
}

і в межах вашого завдання (додайте спробу / нарешті)

latch.countDown();

3
Немає 4 завдань. Існує "деяка кількість завдань", виконаних 4 за один раз.
клент

2
Вибачте, я неправильно зрозумів питання. Так, кількість завдань має бути аргументом конструктора CountDownLatch
ChssPly76

3
Я вважаю це рішення більш елегантним, ніж інші, схоже, воно було зроблене для цієї мети, і воно просте і просте.
wvdschel

3
Що робити, якщо перед початком роботи ви не знаєте кількості завдань?
клент

11
@cletus - тоді ти не використовуєш CountDownLatch :-) Вважаю, я не стверджую, що такий підхід кращий за твій. Тим НЕ менше, я виявив , що в реальних життєвих сценаріїв , я дійсно знаю , кількість завдань, налаштування пулу потоків дійсно потрібно бути налаштованим в розгортанні і басейни можуть бути використані повторно. Тож зазвичай у мене є пул потоків, які вводяться Spring і встановлюють їх як прототипи та вимикають їх вручну лише для того, щоб чекати, коли нитки закінчуються, здається менш ідеальним.
ChssPly76

82

ExecutorService.invokeAll() робить це за вас.

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
List<Callable<?>> tasks; // your tasks
// invokeAll() returns when all tasks are complete
List<Future<?>> futures = taskExecutor.invokeAll(tasks);

Складність виникає, якщо / коли у вас запускаються нитки "4" одна за одною,
поступово

@rogerdpack: Я досі вивчаю цього виконавця та інше. Але у відповідь на те, що ви просите. Чи не повинні 4 потоки одночасно бути частиною пакетної задачі, яка виконується за допомогою відповіді вище?
Mukul Goel

3
Цей метод працюватиме лише в тому випадку, якщо ви знаєте кількість завдань перед вами.
Костянтин

3
Я думаю, що після futuresповернення завдання не виконані. Вони можуть завершитись у майбутньому, і ви отримаєте посилання на результат. Ось чому його називають а Future. У вас є метод Future.get () , який чекатиме завершення завдання, щоб отримати результат.
АлікЕльзін-кілака

5
@ AlikElzin-kilaka Цитата з JavaDocs (пов’язана у відповіді): "Виконує задані завдання, повертаючи список Майбутніх ф'ючерсів з їх статусом та результатами, коли всі завершені. Future.isDone () справедливо для кожного елемента повернутого списку. "
Халк

47

Ви також можете використовувати Списки ф’ючерсів:

List<Future> futures = new ArrayList<Future>();
// now add to it:
futures.add(executorInstance.submit(new Callable<Void>() {
  public Void call() throws IOException {
     // do something
    return null;
  }
}));

тоді, коли ви хочете приєднатись до всіх, це, по суті, еквівалент приєднання до кожного (з додатковою перевагою, що він знову збільшує винятки з дочірніх ниток до основних):

for(Future f: this.futures) { f.get(); }

В основному хитрість полягає в тому, щоб викликати .get () на кожному Майбутнім по одному, замість нескінченного циклічного виклику isDone () увімкнено (усі або кожен). Таким чином, ви гарантовано переходите до цього блоку та проходите його, як тільки закінчується останній потік. Застереження полягає в тому, що оскільки виклик .get () повторно збільшує винятки, якщо один з потоків помирає, ви могли б підняти з цього, можливо, до того, як інші потоки будуть закінчені [щоб уникнути цього, ви можете додати catch ExecutionExceptionнавколо виклику get ]. Інший застереження полягає в тому, що він зберігає посилання на всі потоки, тому, якщо вони мають локальні змінні потоку, вони не збираються, поки не пройдете цей блок (хоча ви, можливо, зможете обійти це, якщо це стане проблемою, видаливши Майбутнє поза ArrayList). Якщо ви хотіли знати, яке майбутнє "закінчується першим"https://stackoverflow.com/a/31885029/32453


3
Щоб знати, що "закінчується першим", використовуйте ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
ToolmakerSteve

34

У Java8 ви можете це зробити за допомогою CompletableFuture :

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

3
Це дуже елегантне рішення.
mattvonb

ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
користувач2862544

@AdamSkywalker очікує випробування (), необхідного після es.shutdown ()?
gaurav

@gaurav, коли ви викликаєте вимкнення, деякі завдання ще не закінчені. Так чекайте, що випробування заблокує викликову нитку, поки все не буде зроблено. Це залежить від того, чи потрібно чекати результатів у цій темі чи ні.
AdamSkywalker

@AdamSkywalker чудова відповідь. має сенс не дзвонити на awaitTermina (), якщо мені не потрібно чекати результатів.
gaurav

26

Всього два мої копійки. Щоб подолати вимогу CountDownLatchзаздалегідь знати кількість завдань, ви можете зробити це за старим способом, використовуючи простий Semaphore.

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

try {
    s.aquire(numberOfTasks);
...

У своєму завданні просто зателефонуйте так, s.release()як хотілося бlatch.countDown();


Побачивши це, я спершу задумався, чи буде проблема, якщо деякі releaseдзвінки відбудуться перед acquireвикликом, але прочитавши документацію на Semaphore, я бачу, що це нормально.
ToolmakerSteve

13

Трохи запізнюємось на гру, але заради завершення ...

Замість того, щоб "чекати" завершення всіх завдань, ви можете думати з точки зору голлівудського принципу: "Не дзвоніть мені, я зателефоную вам" - коли я закінчу. Я думаю, що отриманий код є більш елегантним ...

Гуава пропонує кілька цікавих інструментів для цього.

Приклад ::

Оберніть службу ExecutorService в ListeningExecutorService ::

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

Надіслати колекцію дзвінків на виконання ::

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

Тепер важлива частина:

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

Приєднайте зворотний виклик до ListenableFuture, про який ви можете отримувати сповіщення, коли всі ф'ючерси завершені:

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

Це також пропонує перевагу, що ви можете зібрати всі результати в одному місці, коли обробка закінчена ...

Більше інформації тут


2
Дуже чисто. Працює бездоганно навіть на Android. Просто довелося використовувати runOnUiThread()в onSuccess().
DSchmidt

12

Клас CyclicBarrier на Java 5 і пізніших версіях призначений для подібних речей.


7
Класно, ніколи не можна згадати назву цієї структури даних. Однак підходить лише в тому випадку, якщо ви заздалегідь знаєте кількість завдань, які будуть на черзі.
ᆼ ᆺ ᆼ

так, ви б могли подумати, що вам вдасться вдарити бар’єр поточною ниткою та всіма дочірніми нитками, тоді, коли ви
пройдете

Насправді це неправильна відповідь. CyclicBarrier призначений для порцій. CountDownLatch розрахований на очікування події
gstackoverflow

7

Дотримуйтесь одного з підходів нижче.

  1. Ітерація всіх майбутніх завдань, повернутих з submitна ExecutorServiceі перевірити статус з блокуванням виклику get()на Futureоб'єкті в відповідно до пропозицієюKiran
  2. Використовуйте invokeAll()в ExecutorService
  3. CountDownLatch
  4. ForkJoinPool або Executors.html # newWorkStealingPool
  5. Використовуйте shutdown, awaitTermination, shutdownNowAPI ThreadPoolExecutor у правильній послідовності

Питання, пов'язані з ДП:

Як CountDownLatch використовується в багатопотоковій програмі Java?

Як правильно відключити java ExecutorService


6

ось два варіанти, просто трохи переплутайте, який із них найкраще піти.

Варіант 1:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

Варіант 2:

ExecutorService es = Executors.newFixedThreadPool(4);
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
    futures.add(es.submit(task));
}

for(Future<?> future : futures) {
    try {
        future.get();
    }catch(Exception e){
        // do logging and nothing else
    }
}
es.shutdown();

Тут розміщуємо future.get (); у спробу ловити - це гарна ідея?


5

Ви можете обернути свої завдання в інший запуску, який надсилатиме сповіщення:

taskExecutor.execute(new Runnable() {
  public void run() {
    taskStartedNotification();
    new MyTask().run();
    taskFinishedNotification();
  }
});

1
Мені довелося деякий час бачити, як це вирішить питання ОП. По-перше, зауважте, що це обгортання - це кожне завдання, а не код, який починає всі завдання. Імовірно, кожен початок збільшував би лічильник, а кожен фініш зменшував би цей лічильник, або збільшував би completedлічильник. Тож після запуску їх усі, при кожному повідомленні, могли визначити, чи всі завдання виконані. Зауважте, що важливо використовувати try/finallyтак, щоб готове сповіщення (або альтернативне повідомлення в catchблоці) було надане, навіть якщо завдання не виконане. Інакше зачекав би вічно.
ToolmakerSteve

3

Я щойно написав зразок програми, яка вирішує вашу проблему. Конкретної реалізації не було, тому я додам її. Хоча ви можете використовувати це, executor.shutdown()і executor.awaitTermination()це не найкраща практика, оскільки час, зайнятий різними потоками, був би непередбачуваним.

ExecutorService es = Executors.newCachedThreadPool();
    List<Callable<Integer>> tasks = new ArrayList<>();

    for (int j = 1; j <= 10; j++) {
        tasks.add(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                int sum = 0;
                System.out.println("Starting Thread "
                        + Thread.currentThread().getId());

                for (int i = 0; i < 1000000; i++) {
                    sum += i;
                }

                System.out.println("Stopping Thread "
                        + Thread.currentThread().getId());
                return sum;
            }

        });
    }

    try {
        List<Future<Integer>> futures = es.invokeAll(tasks);
        int flag = 0;

        for (Future<Integer> f : futures) {
            Integer res = f.get();
            System.out.println("Sum: " + res);
            if (!f.isDone()) 
                flag = 1;
        }

        if (flag == 0)
            System.out.println("SUCCESS");
        else
            System.out.println("FAILED");

    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

Добре, що ви показуєте використання future.get - хорошої альтернативи, про яку потрібно знати. Але чому ви вважаєте, що краще почекати назавжди , ніж встановлювати якийсь максимально прийнятний час? Що ще важливіше, немає ніякої причини робити всю цю логіку, коли можна просто дати дійсно, дуже довго чекати випробування, якщо ви хочете чекати (по суті назавжди), поки всі завдання не завершаться.
ToolmakerSteve

Це не відрізняється від представлених тут рішень. Ваше справедливе рішення те саме, що представлено @sjlee
pulp_fiction

Не впевнений, чому потрібно перевірити, чи зроблено, коли згідно з Oracle doc, invokeAll повернеться лише "коли все закінчиться або час закінчиться, залежно від того, що відбудеться першим"
Mashrur

3

Просто, щоб запропонувати більше альтернатив, тут різні для використання засувок / бар'єрів. Ви також можете отримати часткові результати, поки всі вони не закінчать використовувати CompletionService .

З практичної роботи Java Concurrency: "Якщо у вас є група обчислень, які потрібно подати виконавцю, і ви хочете отримати їх результати, коли вони стануть доступними, ви можете зберегти майбутнє, пов'язане з кожним завданням, і повторно опитуватись для завершення, зателефонувавши get with a тайм-аут нуля. Це можливо, але нудно . На щастя, є кращий спосіб : послуга по завершенню ».

Тут реалізація

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

3

Це моє рішення, засноване на підказці "AdamSkywalker", і воно працює

package frss.main;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestHilos {

    void procesar() {
        ExecutorService es = Executors.newFixedThreadPool(4);
        List<Runnable> tasks = getTasks();
        CompletableFuture<?>[] futures = tasks.stream().map(task -> CompletableFuture.runAsync(task, es)).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(futures).join();
        es.shutdown();

        System.out.println("FIN DEL PROCESO DE HILOS");
    }

    private List<Runnable> getTasks() {
        List<Runnable> tasks = new ArrayList<Runnable>();

        Hilo01 task1 = new Hilo01();
        tasks.add(task1);

        Hilo02 task2 = new Hilo02();
        tasks.add(task2);
        return tasks;
    }

    private class Hilo01 extends Thread {

        @Override
        public void run() {
            System.out.println("HILO 1");
        }

    }

    private class Hilo02 extends Thread {

        @Override
        public void run() {
            try {
                sleep(2000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("HILO 2");
        }

    }


    public static void main(String[] args) {
        TestHilos test = new TestHilos();
        test.procesar();
    }
}

2

Ви можете використовувати цей код:

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");

2

Я створив наступний робочий приклад. Ідея полягає в тому, щоб створити спосіб обробки пулу завдань (я використовую чергу як приклад) з багатьма потоками (програмно визначається числомOfTasks / поріг), і зачекати, поки всі потоки будуть завершені, щоб продовжити деяку іншу обробку.

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

Сподіваюся, це допомагає!


1

Ви можете використовувати свій власний підклас ExecutorCompletionService для завершення taskExecutorта власну реалізацію BlockingQueue, щоб отримувати інформацію про те, коли кожне завдання завершується та виконує будь-який зворотний виклик чи іншу дію, яку ви бажаєте, коли кількість виконаних завдань досягне бажаної мети.


1

слід використовувати executorService.shutdown()і executorService.awaitTerminationметод.

Приклад наступний:

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

}

очікує випробування (), необхідного після вимкнення () /
gaurav

1

Тож я розміщую тут свою відповідь із пов'язаного питання, якщо хтось хоче простіший спосіб зробити це

ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture[] futures = new CompletableFuture[10];
int i = 0;
while (...) {
    futures[i++] =  CompletableFuture.runAsync(runner, executor);
}

CompletableFuture.allOf(futures).join(); // THis will wait until all future ready.

0

Java 8 - Ми можемо використовувати API потоку для обробки потоку. Перегляньте фрагмент нижче

final List<Runnable> tasks = ...; //or any other functional interface
tasks.stream().parallel().forEach(Runnable::run) // Uses default pool

//alternatively to specify parallelism 
new ForkJoinPool(15).submit(
          () -> tasks.stream().parallel().forEach(Runnable::run) 
    ).get();

2
Привіт Владе, ласкаво просимо до StackOverflow. Чи можете ви відредагувати свою відповідь, щоб пояснити, як це відповідає на питання і що робить код? Тут відхиляються лише відповіді на код. Дякую!
Тім Малоун

У цій публікації йдеться про одночасність. Паралелізм! = Паралельність
ГабріельББ

0

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

Якщо doSomething()викинути якісь інші винятки, latch.countDown()здається, не буде виконано, і що мені робити?


0

якщо ви використовуєте більше потоків ExecutionServices СЕКВЕНТАЛЬНО і хочете зачекати ВСЕ ВИКОНАННЯ СЕРВІСУ. Найкращий спосіб, як нижче;

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){
 ...
}

-1

Це може допомогти

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

-1

Ви можете зателефонувати waitTillDone () у цьому класі Runner :

Runner runner = Runner.runner(4); // create pool with 4 threads in thread pool

while(...) {
    runner.run(new MyTask()); // here you submit your task
}


runner.waitTillDone(); // and this blocks until all tasks are finished (or failed)


runner.shutdown(); // once you done you can shutdown the runner

Ви можете повторно використовувати цей клас і зателефонувати waitTillDone () стільки разів, скільки хочете, перш ніж вимкнути вимкнення (), плюс ваш код надзвичайно простий . Крім того, ви не повинні знати про кількість завдань заздалегідь.

Для його використання просто додайте цю граду / мавен compile 'com.github.matejtymes:javafixes:1.3.1' залежність від до свого проекту.

Детальніше можна ознайомитись тут:

https://github.com/MatejTymes/JavaFixes


-2

Є у виконавця метод getActiveCount()- який дає кількість активних потоків.

Протягнувши нитку, ми можемо перевірити, чи є activeCount()значення 0. Після того, як значення дорівнює нулю, мається на увазі, що зараз немає активних потоків, що означає, що завдання закінчено:

while (true) {
    if (executor.getActiveCount() == 0) {
    //ur own piece of code
    break;
    }
}

3
Непогана ідея, див. Stackoverflow.com/a/7271685/1166992 та javadoc: "Повертає приблизну кількість потоків, які активно виконують завдання".
Олів'є Фошо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.