подождите, пока все потоки не закончат свою работу на java



Я пишу приложение, которое имеет 5 потоков, которые получают некоторую информацию из интернета одновременно и заполняют 5 различных полей в буферном классе.

Мне нужно проверить данные буфера и сохранить их в базе данных, когда все потоки закончили свою работу.

Как я могу это сделать (получить предупреждение, когда все потоки закончили свою работу) ?

688   13  

13 ответов:

Я должен использовать ExecutorService для управления пулами потоков.

ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<5;i++)
    es.execute(new Runnable() { /*  your task */ });
es.shutdown();
boolean finshed = es.awaitTermination(1, TimeUnit.MINUTES);
// all tasks have finished or the time has been reached.

вы можете join на резьбу. Соединение блоков до тех пор, пока поток не завершится.

for (Thread thread : threads) {
    thread.join();
}

отметим, что join выдает InterruptedException. Вам нужно будет решить, что делать, если это произойдет (например, попробуйте отменить другие потоки, чтобы предотвратить ненужную работу).

посмотреть различные решения.

  1. join() API был представлен в ранних версиях Java. Некоторые хорошие альтернативы доступны с этим одновременно пакет с момента выпуска JDK 1.5.

  2. ExecutorService#invokeAll ()

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

    см. этот связанный вопрос SE для примера кода:

    как использовать invokeAll (), чтобы весь пул потоков выполнял свою задачу?

  3. CountDownLatch за

    средство синхронизации, которое позволяет одному или нескольким потокам ожидать завершения набора операций, выполняемых в других потоках.

    A CountDownLatch за инициализируется заданным рассчитывать. Методы await блокируются до тех пор, пока текущее количество не достигнет нуля из-за вызовов countDown() метод, после которого все ожидающие потоки освобождаются и любые последующие вызовы await возвращаются немедленно. Это одноразовое явление-счетчик не может быть сброшен. Если вам нужна версия, которая сбрасывает счетчик, рассмотрите возможность использования CyclicBarrier.

    обратитесь к этому вопросу для использования CountDownLatch

    как ждать нить, что порождает собственный поток?

  4. ForkJoinPool или newWorkStealingPool () in исполнители

  5. перебрать все будущее объекты, созданные после представления ExecutorService

помимо Thread.join() предложенный другими, java 5 представил структуру исполнителя. Там вы не работаете с Thread объекты. Вместо этого вы отправляете свой Callable или Runnable объекты для исполнителя. Есть специальный исполнитель, который предназначен для выполнения нескольких задач и вернуть их результатов в порядке. Вот это ExecutorCompletionService:

ExecutorCompletionService executor;
for (..) {
    executor.submit(Executors.callable(yourRunnable));
}

тогда вы можете повторно позвонить take() пока больше нет Future<?> объекты для возврата, что означает, что все они являются завершенный.


еще одна вещь, которая может быть актуальна, в зависимости от вашего сценария CyclicBarrier.

помощь синхронизации, которая позволяет набору потоков все ждать друг друга, чтобы достичь общей точки барьера. Циклические барьеры полезны в программах, включающих фиксированный размер партии потоков, которые должны иногда ждать друг друга. Барьер называется циклическим, потому что он может быть повторно использован после освобождения ожидающих потоков.

другая возможность -CountDownLatch объект, который полезен для простых ситуаций: так как вы заранее знаете количество потоков, вы инициализируете его с соответствующим количеством и передаете ссылку объекта на каждый поток.
По завершении своей задачи, каждый поток вызывает CountDownLatch.countDown(), который уменьшает внутренний счетчик. Основной поток, после запуска всех остальных, должен сделать CountDownLatch.await() блокировка вызова. Он будет выпущен как только внутренний счетчик достиг 0.

обратите внимание, что с этим объектом, an InterruptedException может быть брошен, а также.

ты

for (Thread t : new Thread[] { th1, th2, th3, th4, th5 })
    t.join()

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

хранить Thread-объекты в некоторую коллекцию (например, список или набор), а затем цикл через коллекцию после запуска потоков и вызов join () на резьбе.

можно использовать Threadf#join метод для этой цели.

хотя это не относится к проблеме OP, если вы заинтересованы в синхронизации (точнее, рандеву) с ровно одним потоком, вы можете использовать обменник

в моем случае мне нужно было приостановить Родительский поток, пока дочерний поток не сделал что-то, например, завершил его инициализацию. А CountDownLatch за тоже хорошо работает.

служба исполнителя может использоваться для управления несколькими потоками, включая состояние и завершение. См.http://programmingexamples.wikidot.com/executorservice

попробуйте это, будет работать.

  Thread[] threads = new Thread[10];

  List<Thread> allThreads = new ArrayList<Thread>();

  for(Thread thread : threads){

        if(null != thread){

              if(thread.isAlive()){

                    allThreads.add(thread);

              }

        }

  }

  while(!allThreads.isEmpty()){

        Iterator<Thread> ite = allThreads.iterator();

        while(ite.hasNext()){

              Thread thread = ite.next();

              if(!thread.isAlive()){

                   ite.remove();
              }

        }

   }

У меня была аналогичная проблема, и в итоге я использовал Java 8 parallelStream.

requestList.parallelStream().forEach(req -> makeRequest(req));

это очень просто и читабельно. За кулисами он использует пул fork join по умолчанию JVM, что означает, что он будет ждать завершения всех потоков, прежде чем продолжить. Для моего случая это было аккуратное решение, потому что это был единственный параллельный поток в моем приложении. Если у вас есть несколько параллельных потоков, работающих одновременно, пожалуйста, прочитайте ссылку ниже.

больше информации о параллельных потоках здесь.

используйте это в своем основном потоке: while(!исполнитель.isTerminated()); Поместите эту строку кода после запуска всех потоков из службы исполнителя. Это приведет только к запуску основного потока после завершения всех потоков, запущенных исполнителями. Убедитесь, что для вызова исполнителя.shutdown (); перед вышеуказанным циклом.

Comments

    Ничего не найдено.