2013-05-17 3 views
1

У меня есть класс, к которому обращаются несколько потоков, каждый поток запрашивает один метод этого класса. Каждый метод, в свою очередь, выполняет количество Callables. Этот класс использует threadPool из ExecutorService для выполнения этих Callables посредством метода invokeAll ((Collection>) executableTasks). Установка выглядит следующим образом:invokeAll vs CompletionService

public MyClass { 
private final ExecutorService threadPool = Runtime.getRuntime().availableProcessors(); 

public void method1() { 
List<SomeObject> results = new ArrayList<>(); 
List<Callable<Void>> tasks = new ArrayList<Callable<Void>>(); 
tasks.add(new Callable<Void>(){ ... results.add(someObject);}); 
threadPool.invokeAll(tasks); 
} 

public void method2() { 
List<SomeObject> results = new ArrayList<>(); 
List<Callable<Void>> tasks = new ArrayList<Callable<Void>>(); 
tasks.add(new Callable<Void>(){ ... results.add(someObject);}); 
threadPool.invokeAll(tasks); 
} 

} 

Я смущен, если это будет выполнять задачи в классе одновременно или invokeAll() блокирует выполнение до задач в один метод завершается (означает выполнение будет происходить одновременно внутри методов, но не в классе уровень)? Или я должен использовать CompletionService для поиска соответствующих результатов задач?

ответ

2

ExecutorService#invokeAll выполняет все задачи одновременно, но сам вызов блокируется до тех пор, пока все задачи не будут завершены ,

Например, допустим, что у вас есть три задачи, которые занимают 6 сек, 2 секунды и 10 секунд для завершения. Если бы вы выполняли эти синхронно, это заняло бы не менее 6 + 2 + 10 = 18 секунд. Однако, используя invokeAll (на достаточно большом пуле потоков), это может занять до самого длинного времени или 10 секунд.

Это означает, что методы и method2() являются одновременно блокирующими методами из-за использования invokeAll(). Когда вы вызываете method1(), он будет блокироваться до тех пор, пока все запросы, добавленные в список вызываемых вызовов, не будут завершены. То же самое касается method2(). Если эти методы вызывают из разных потоков, то задачи обоих методов будут выполняться одновременно.

Если вы хотите, чтобы методы были асинхронными, вам нужно вызвать threadPool.submit (вызываемый) отдельно для каждой задачи внутри методов и собрать возвращенные фьючерсы в списке. Вы можете либо вернуть список, либо использовать CompletionService, чтобы помочь в этом, да.

PS - это строка в вашем примере не будет работать:

ExecutorService threadPool = Runtime.getRuntime().availableProcessors(); 

Я думаю, что вы хотите вместо этого:

ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 

Надеется, что это помогает.

+0

«Итак, да, выполнение будет выполняться одновременно в рамках определенного метода, но не на уровне класса»: но эти 2 метода вызывают в 2 разных потоках, то почему эти задачи (из метода1 и method2) не будут выполняться одновременно –

+1

Упс, я полагаю, должно было прочитать первое предложение. Я исправил свой ответ. Спасибо за совет! –

+0

@Cody Согласитесь с обоими предложениями: методы блокирования и опечатки в определении threadPool. – Smithsonian

-1

В соответствии с Спецификацией Java invokeAll выполнять все задачи одновременно независимо друг от друга. и повторные вызовы на invokeAll будут делать то же самое, то есть вызов invokeAll не блокирует выполнение задач.

визит: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/AbstractExecutorService.html

+1

в нем говорится: Выполняет заданные задачи, ** возвращает ** список фьючерсов, содержащих их статус и результаты **, когда все завершено **. –

0

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

+0

Да, выполнение также поддерживает это. Я был в замешательстве с людьми, комментируя «invokeAll ждет, пока все задачи не будут завершены». – Smithsonian

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