Ожидание подмножества потоков в Java ThreadPool - PullRequest
1 голос
/ 08 января 2011

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

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

Если бы метод execute() пула потоков возвратил ссылку на занятый поток, я мог бы просто join() на каждый из этих Y потоков, но это не так.

Кто-нибудь знает элегантный способ сделать это? Спасибо.

Ответы [ 4 ]

3 голосов
/ 08 января 2011

Вы можете использовать CyclicBarrier, и каждый поток ожидает только, когда он имеет тип Y. Например.

ExecutorService executor = Executors.newFixedThreadPool(X.size);

public void executeAllAndAwaitCompletion(List<? extends Y> myRunnableY){
   final CyclicBarrier barrier = new CyclicBarrier(myRunnable.size()+1);
   for(final Y y : myRunnableY){
       executor.submit(new Runnable(){
           public void run(){
                y.run();//for the sake of this example y has a run method
                barrier.await();
           }
       }); 
    }
   barrier.await();
}

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

Также Примечание: Если пример Майкла Боргвардта работает для вас, это будет лучше.Однако, если вам нужен пул потоков, для каждого потока, на котором выполняется Y, чтобы не запускать другие не-Y, тогда мое решение будет единственным способом, которым вы можете это сделать.Future.get () будет блокировать только вызывающий поток, а когда пул потоков завершит выполнение Y, он затем подхватит какую-то другую (возможно, не Y) задачу.

3 голосов
/ 08 января 2011

Вместо execute() ing Runnable s, просто invokeAll() some Callable s - тогда вы получите Future для каждого, по которому вы можете позвонить get(), что блокируетпока задача не будет завершена.

2 голосов
/ 08 января 2011

Вы должны использовать CompletionService, который используется именно для этой цели.

  • Создать Executor
  • Создать ExecutorCompletionService с помощью Исполнителя
  • Отправляйте задачи с помощью CompletionService
  • Используйте take или poll на CompletionService, чтобы дождаться завершения задач
  • Повторяйте, пока все отправленные вами задачи не будут завершены
  • Готово

Вы можете поделиться Исполнителем с чем-то другим, просто создайте CompletionService поверх и используйте его для своих конкретных задач.

0 голосов
/ 30 ноября 2013

Создайте CountDownLatch с Y в качестве числа и выполните latch.countDown() в каждой из Y задач. В конце концов latch.await() обеспечит выполнение всех задач Y.

...