2015-04-04 3 views
1

Я знаю, что shutdown() и awaitTermination() есть. Проблема состоит в том, что в пулах в пуле должно быть возможно добавить неизвестное число (не может использовать countdownlatch) других runnables, и если я вызову shutdown(), эти задачи будут отклонены. Как я могу узнать, когда они будут сделаны?Как узнать, когда все потоки в ExecutorService закончены?

+0

Когда задача ('Runnable') T порождает другие n задач, вы могли бы сказать, что эта задача T выполняется, когда все эти n задач выполнены? Итак, существует (концептуальная) зависимость между задачей T и ее подзадачами? – isnot2bad

+0

Справа.Я забыл, что я использую 'newFixedThreadPool', где максимальное количество работающих потоков - это количество процессоров. Как только один runnable порождает других, для этого больше не нужно работать. Если бы он ждал, пока исполняемые файлы, которые он породил, закончили, он просто сидит там, ничего не делая, и программа никогда не закончится из-за ограничения количества потоков. – user2980766

+0

Поэтому вы должны, вероятно, использовать 'ForkJoinTask'. – isnot2bad

ответ

0

Вместо отправки Runnable задач на Executor, вы должны использовать вместо этого ForkJoinTask/ForkJoinPool. A ForkJoinTask работает внутри ForkJoinPool и может порождать произвольное количество (под) задач и ждать их завершения, фактически не блокируя текущий поток. A ForkJoinTask завершен, когда все его подзадачи выполнены, поэтому выполняется полное вычисление, когда начальный (корень) ForkJoinTask завершен.

Для получения более подробной информации см. Oracle - The Java™ Tutorials - Fork/Join.

Поскольку все ваши задачи являются безрезультатными (Runnable), вы должны подкласс RecursiveAction (который сам по себе является подклассом ForkJoinTask). Внесите метод compute() и создайте произвольное количество новых задач там, вызывая invoke(subtask), invokeAll(subtask1, subtask2, ...) или subtask.fork(), а затем subtask.join().

Весь расчет выполняется следующим образом:

MyRecursiveAction task = new MyRecursiveAction(params); 
ForkJoinPool pool = new ForkJoinPool(numberOfThreads); 
pool.invoke(task); // will block until task is done 

Unfortunatley преимущества вилки/Join имеют некоторые ограничения, например:

(...) Вычисления в идеале должны избегать синхронизированных методов или блоки и должны минимизировать другую блокирующую синхронизацию, помимо объединения других задач или с использованием синхронизаторов, таких как Phasers, которые рекламируются для сотрудничества с планированием fork/join. Субдивидируемые задачи также должны не выполнять блокировку ввода-вывода и должны идеально обращаться к переменным, которые полностью независимы от тех, к которым выполняются другие запущенные задачи. Эти директивы слабо применяются, если не разрешены проверенные исключения , такие как IOExceptions, которые должны быть выбраны. (...)

Подробнее см. API docs of ForkJoinTask.

+0

Этот способ лучше всего подходит для ответов. Благодарю. – user2980766

1

Работает с Future, а не с Runnable. Вот этот метод Future#isDone, который может вам помочь.

Если у вас нет ничего значимого для возврата из Callable, используйте Callable<Void> и Future<Void>.

0

Если вы в состоянии использовать Guava Futures, вы можете использовать Futures.allAsList или Futures.successfulAsList. Это позволяет вам обернуть несколько экземпляров Future, которые вы получили от ExecutorService, в один Future, который затем вы можете проверить, будет ли он закончен с использованием isDone() (или просто get(), если на то пошло, если вы хотите заблокировать до завершения).

Смежные вопросы