Каков наилучший способ дождаться завершения потока ThreadPoolExecutor в java?

Я использую ThreadPoolExecutor в java для выполнения нескольких потоков, и мне нужно что-то делать после завершения потоков и ждать.

Вот я и хочу спросить, как лучше это сделать?

Правильно ли я делаю в пути?

threadPool.shutdown();

boolean loop = true;
Integer x = threadPool.getPoolSize();
while (threadPool.getPoolSize() != 0) {
}

person jsohpill    schedule 25.03.2016    source источник


Ответы (2)


Завершение работы инициирует упорядоченное завершение работы, при котором выполняются ранее отправленные задачи, но новые задачи приниматься не будут.

    executor.shutdown();
    System.out.println("All tasks submitted...No new tasks will be admitted");

Тем не менее, я настоятельно рекомендую использовать awaitTermination, так как это позволит блокировать текущий поток до тех пор, пока все задачи не завершат выполнение после запроса на завершение работы, или не истечет время ожидания, или текущий поток не будет прерван, в зависимости от того, что произойдет раньше.

    try {
        executor.awaitTermination(3, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

РЕДАКТИРОВАТЬ:

 The runState provides the main lifecyle control, taking on values:

 *   RUNNING:  Accept new tasks and process queued tasks
 *   SHUTDOWN: Don't accept new tasks, but process queued tasks
 *   STOP:     Don't accept new tasks, don't process queued tasks,
 *             and interrupt in-progress tasks
 *   TIDYING:  All tasks have terminated, workerCount is zero,
 *             the thread transitioning to state TIDYING
 *             will run the terminated() hook method
 *   TERMINATED: terminated() has completed

Числовой порядок среди этих значений имеет значение, чтобы можно было проводить упорядоченные сравнения. RunState монотонно увеличивается с течением времени, но не обязательно должно достигаться каждое состояние. Переходы:

РАБОТАЕТ -> ВЫКЛЮЧЕНИЕ
При вызове shutdown(), возможно, неявно в finalize()

(РАБОТАЕТ или ВЫКЛЮЧЕН) -> ОСТАНОВИТЬ
При вызове shutdownNow()

SHUTDOWN -> TIDYING
Когда и очередь, и пул пусты

STOP -> TIDYING
Когда пул пуст

TIDYING -> TERMINATED
После завершения работы метода ловушки terminated(). Потоки, ожидающие в awaitTermination(), будут возвращены, когда состояние достигнет TERMINATED.

Обнаружение перехода из SHUTDOWN в TIDYING не так просто, как хотелось бы, потому что очередь может стать пустой после непустой и наоборот во время состояния SHUTDOWN, но мы можем завершить работу только в том случае, если, увидев, что она пуста, мы видим, что workerCount равно 0.

Возвращаясь к вашему вопросу, когда вы вызываете getPoolSize(), он проверяет состояние пула потоков, когда он находится в состоянии TIDYING. Следовательно, я думаю, что правильная проверка должна быть против состояния TERMINATED. Хотя результаты будут такими же, если вы не реализовали метод terminated().

person Suparna    schedule 25.03.2016
comment
Две причины: 1. while loop будет привязан к процессору, пока ваш пул потоков не завершит выполнение. С другой стороны, это не относится к awaitTermination 2. Состояние исполнителя еще не завершено, когда вы используете getPoolSize(). Хотя, возможно, вы не реализовали вызов terminated(), и, следовательно, все должно быть в порядке. Но для № 1 я рекомендую awaitTermination вместо цикла while. - person Suparna; 25.03.2016
comment
Но он не может дождаться завершения всех потоков, если просто использовать try { executor.awaitTermination(3, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } . после этого основной процесс продолжит выполнение кода. Кажется, необходимо использовать while, чтобы остановить основной процесс, продолжающийся до завершения потоков. - person jsohpill; 25.03.2016
comment
извините, я использовал это из одного из моих примеров, где я хотел подождать 3 секунды. Вы можете изменить его на: executor.awaitTermination(3, TimeUnit.DAY); - person Suparna; 25.03.2016
comment
:-) Спасибо за помощь. Я все еще использую while, потому что я должен дождаться завершения всего потока, и я использую awaitTermination. try { while (!threadPool.awaitTermination(1, TimeUnit.SECONDS)) { } } catch (InterruptedException e) { e.printStackTrace(); } - person jsohpill; 28.03.2016
comment
Без проблем. Просто чтобы, если вы нашли информацию полезной, вы могли проголосовать за ответ, а также выбрать лучший ответ. Вы также получите кредит за закрытие вопроса. - person Suparna; 28.03.2016

Если вы хотите изящно подождать, обратитесь к решениям в следующем вопросе:

Как дождаться завершения нескольких задач на Java?

Если вы не используете ни один из них ( invokeAll, CountDownLatch) и отправляете задания и ждете, пока исполнитель завершит выполнение задач, см.

Как принудительно отключить java ExecutorService

Базовый фрагмент кода в этом случае:

void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
person Ravindra babu    schedule 25.03.2016