Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
 ExecutorService: как дождаться нормального завершения всех потоков?  [new]
Molasar
Member

Откуда:
Сообщений: 700
Всем привет!

Как дождаться нормального завершения всех потоков и только потом разорвать соединение?
В текущем примере jmsSender.disconnect() срабатывает, не дожидаясь завершения потоков.

ExecutorService executor = Executors.newCachedThreadPool();
JmsSender jmsSender = JmsSender.getInstance();
jmsSender.connect();

for (int i = 1; i <= maxThreads; i++) {
      eventList = new ArrayList<>();
      eventList = generateEvents(eventList, app + i);
      executor.execute(new JmsProducer(app + i, queue, eventList));
}

executor.shutdown();

while (!executor.isShutdown()) {
}
        
jmsSender.disconnect();
26 апр 19, 15:43    [21872787]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
забыл ник
Member

Откуда:
Сообщений: 2832
Molasar,

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#awaitTermination-long-java.util.concurrent.TimeUnit-
26 апр 19, 16:01    [21872804]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 7703
Molasar
...
while (!executor.isShutdown()) {
}
...

Увидев такое, тут же хочется вспомнить слова из "великого и могучего" русского языка и закрыть тему.
26 апр 19, 16:25    [21872833]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
mayton
Member

Откуда: loopback
Сообщений: 41059
Вот тут стандартный пример есть https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
как правильно тушить ExecutorService.

Только весь прикладной код что выше написан скорее всего неправильный. В нем есть race conditions.
26 апр 19, 16:58    [21872865]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
Molasar
Member

Откуда:
Сообщений: 700
Спасибо за идею!
В итоге получилось:
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
jmsSender.disconnect();
26 апр 19, 17:04    [21872875]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
mayton
Member

Откуда: loopback
Сообщений: 41059
Что получилось? Твои JmsProducer-ы что-то хоть сделали?
26 апр 19, 17:09    [21872877]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
Molasar
Member

Откуда:
Сообщений: 700
mayton
Вот тут стандартный пример есть https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
как правильно тушить ExecutorService.

Только весь прикладной код что выше написан скорее всего неправильный. В нем есть race conditions.

Очень интересно ваше мнение по поводу race conditions.

Несколько потоков (JmsProducer) кидают в очередь ActiveMQ объекты Event, использую одно подключение - JmsSender.
Каждый созданный класс JmsProducer implements Runnable:
@Override
    public void run() {
        System.out.println(name + " - " + jmsSender);
        eventList.forEach((event) -> {
            try {
                jmsSender.send(event, queue);
            } catch (JMSException ex) {
                Logger.getLogger(JmsProducer.class.getName())
                        .log(Level.SEVERE, null, ex);
            }
        });
    }

class JmsSender - синглтон:
public void send(Event event, String queue) throws JMSException {
        MessageProducer producer = session.createProducer(
                session.createQueue(queue));
        
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        producer.send(session.createObjectMessage(event));
    }
26 апр 19, 17:15    [21872884]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
Molasar
Member

Откуда:
Сообщений: 700
mayton
Что получилось? Твои JmsProducer-ы что-то хоть сделали?

Да, всё сгенерированные сообщения были успешно поставлены в очередь.
26 апр 19, 17:26    [21872887]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
забыл ник
Member

Откуда:
Сообщений: 2832
Нормально все у тебя с race conditions, точнее их нет
26 апр 19, 17:26    [21872889]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
mayton
Member

Откуда: loopback
Сообщений: 41059
Не нравится мне такая практика. Давайте вычитаем как работает ::shutdown().

Мне кажется есть риск что мы срубим на взлёте часть JmsProducer-s.
26 апр 19, 17:29    [21872894]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
mayton
Member

Откуда: loopback
Сообщений: 41059
Возьму документацию от восьмёрки.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks.

An ExecutorService can be shut down, which will cause it to reject new tasks. Two different methods are provided for shutting down an ExecutorService. The shutdown() method will allow previously submitted tasks to execute before terminating, while the shutdownNow() method prevents waiting tasks from starting and attempts to stop currently executing tasks. Upon termination, an executor has no tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused ExecutorService should be shut down to allow reclamation of its resources.

Method submit extends base method Executor.execute(Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write customized variants of these methods.)

The Executors class provides factory methods for the executor services provided in this package.


Хм... ну может быть. Кто уже сделал перевод и скажет заключение?
26 апр 19, 17:34    [21872904]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
Molasar
Member

Откуда:
Сообщений: 700
mayton
Возьму документацию от восьмёрки.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks.

An ExecutorService can be shut down, which will cause it to reject new tasks. Two different methods are provided for shutting down an ExecutorService. The shutdown() method will allow previously submitted tasks to execute before terminating, while the shutdownNow() method prevents waiting tasks from starting and attempts to stop currently executing tasks. Upon termination, an executor has no tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused ExecutorService should be shut down to allow reclamation of its resources.

Method submit extends base method Executor.execute(Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write customized variants of these methods.)

The Executors class provides factory methods for the executor services provided in this package.


Хм... ну может быть. Кто уже сделал перевод и скажет заключение?

Т.е. shutdown может быть вызван до того, как ExecutorService запустит все JmsProducer?
26 апр 19, 17:44    [21872917]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
забыл ник
Member

Откуда:
Сообщений: 2832
Вообще, в твоем случае лучше и вправду сконструировать список Callable и затем пульнуть их пачкой через invokeAll, тогда и shutdown не нужен
26 апр 19, 18:05    [21872925]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
забыл ник
Member

Откуда:
Сообщений: 2832
mayton

Хм... ну может быть. Кто уже сделал перевод и скажет заключение?

В данном случае все ок, но лучше работать через invokeAll
26 апр 19, 18:07    [21872927]     Ответить | Цитировать Сообщить модератору
 Re: ExecutorService: как дождаться нормального завершения всех потоков?  [new]
mayton
Member

Откуда: loopback
Сообщений: 41059
забыл ник
Вообще, в твоем случае лучше и вправду сконструировать список Callable и затем пульнуть их пачкой через invokeAll, тогда и shutdown не нужен

Фьючерс или CoundDownLatch я-бы использовал чтоб не зависеть от системного shutdown. Всё таки
он больше связан с завершением работы приложения.
26 апр 19, 18:46    [21872949]     Ответить | Цитировать Сообщить модератору
Все форумы / Java Ответить