Исполнители Java: дождитесь завершения задачи.
Мне нужно отправить несколько задач, а затем дождаться их, пока не будут доступны все результаты. Каждый из них добавляет String
в Vector
(который по умолчанию синхронизируется). Затем мне нужно начать новую задачу для каждого результата в Vector, но мне нужно сделать это, только когда все предыдущие задачи перестали выполнять свою работу.
Я хочу использовать Java Executor, в частности, я попытался использовать Executors.newFixedThreadPool(100)
, чтобы использовать фиксированное число потоков (у меня есть переменное число задач, которое может быть 10 или 500), но я новичок с исполнителями и Я не знаю, как ждать завершения задачи.
Это что-то вроде псевдокода моей программы:
ExecutorService e = Executors.newFixedThreadPool(100);
while(true){
/*do something*/
for(...){
<start task>
}
<wait for all task termination>
for each String in result{
<start task>
}
<wait for all task termination>
}
Я не могу выполнить e.shutdown, потому что я некоторое время (правда), и мне нужно повторно использовать executorService
...
Вы можете мне помочь? Можете ли вы предложить мне путеводитель/книгу о исполнителях java?
Ответы
Ответ 1
ExecutorService
предоставляет вам механизм для одновременного выполнения нескольких задач и получения коллекции объектов Future
назад (представляющих асинхронное вычисление задачи).
Collection<Callable<?>> tasks = new LinkedList<Callable<?>>();
//populate tasks
for (Future<?> f : executorService.invokeAll(tasks)) { //invokeAll() blocks until ALL tasks submitted to executor complete
f.get();
}
Если у вас есть Runnable
вместо Callable
s, вы можете легко превратить Runnable
в Callable<Object>
с помощью метода:
Callable<?> c = Executors.callable(runnable);
Ответ 2
Можете ли вы предложить мне путеводитель/книгу о java-исполнители
Я могу ответить на эту часть:
Java Concurrency на практике Брайана Гетца (с Тимом Пайерлсом, Джошуа Блох, Джозеф Боубэр, Дэвид Холмс и Дуг Лиа), скорее всего, ваш лучший выбор.
![l3bFn.jpg]()
Это не только об исполнителях, но и охватывает пакет java.util.concurrent
в целом, а также основные понятия и методы Concurrency и некоторые дополнительные темы, такие как модель памяти Java.
Ответ 3
Вместо отправки Runnable
или Callable
в Executor
напрямую и сохранения соответствующих возвращаемых значений Future
я бы рекомендовал использовать реализацию CompletionService
для извлечения каждого Future
, когда он завершает. Этот подход отделяет производство задач от потребления завершенных задач, позволяя, например, создавать новые задачи в потоке производителя за определенный промежуток времени.
Collection<Callable<Result>> workItems = ...
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletionService<Result> compService = new ExecutorCompletionService<Result>(executor);
// Add work items to Executor.
for (Callable<Result> workItem : workItems) {
compService.submit(workItem);
}
// Consume results as they complete (this would typically occur on a different thread).
for (int i=0; i<workItems.size(); ++i) {
Future<Result> fut = compService.take(); // Will block until a result is available.
Result result = fut.get(); // Extract result; this will not block.
}
Ответ 4
Когда вы отправляете службе исполнителя, вы получите объект Future.
Сохраните эти объекты в коллекции, а затем вызовите get() по очереди. get()
блокируется до завершения базового задания, и поэтому результатом является то, что вызов get()
для каждого будет завершен после завершения всех базовых заданий.
например.
Collection<Future> futures = ...
for (Future f : futures) {
Object result = f.get();
// maybe do something with the result. This could be a
// genericised Future<T>
}
System.out.println("Tasks completed");
Как только все это закончится, начните свое второе представление. Обратите внимание, что это может быть не оптимальное использование пула потоков, поскольку оно станет бездействующим, а затем вы его повторно заселяете. Если возможно, попробуйте и не забудьте заняться делами.
Ответ 5
ExecutorService executor = ...
//submit tasks
executor.shutdown(); // previously submitted tasks are executed,
// but no new tasks will be accepted
while(!executor.awaitTermination(1, TimeUnit.SECONDS))
;
Нет простого способа сделать то, что вы хотите, без создания пользовательского ExecutorService.