Как правильно выполнять задачи с асинхронным таймаутом в Java 8 - PullRequest
2 голосов
/ 11 октября 2019

У меня есть однопоточный исполнитель, который считывает исходящие задания из очереди блокировки, так как я должен отправлять электронные письма последовательно. Иногда зависает вызов sendMail () отправителя java почты. Так как у меня есть только один поток, отправляющий электронную почту, я не хочу останавливать это на неопределенный срок, когда зависает вызов почтового сервера.

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

То, как я это сделал, - это класс Java 8 Future. Поэтому я отправляю задачу моему однопоточному исполнителю, получаю в будущем объект будущих объектов, а затем планирую future.cancel () в отдельном scheduleExecutor. При использованииланированного исполнителя мой основной поток, который обрабатывает задания электронной почты из очереди блокировки, остается асинхронным.

Но у этого подхода есть проблема. Допустим, в очереди на блокировку есть 5 объектов, которые нужно отправить по электронной почте. И давайте предположим, что у меня есть тайм-аут 5 секунд, после которого будет вызван future.cancel (). Мой поток асинхронного удаления из очереди быстро проходит и помещает все 5 объектов в очередь однопоточного исполнителя. И когда мой единственный поток выбирает первое задание и вызывает JavaMail's-> sendMail (), вызов зависает. Через 5 секунд в этой задаче будет вызван future.cancel (). Но мои остальные 4 задания были также в очереди исполнителя в течение последних 5 секунд, поэтому их future.cancel () также будет вызываться даже до того, как они будут обработаны одним потоком!

Вот моя существующая реализация


// process sequentially using single 'EmailMain'thread.
Future future = singleThreadExecutor.submit( () -> {
    try {

        mailService.sendEmail( tradeConfirmationInputFields, tradeConfirmFile );
    } catch ( MessagingException | IOException e ) {
        log.error( "Found error", e );
        return;
    }
} );

// timeout the single 'EmailMain' thread if not completed within allowed time.
taskTimeoutScheduledExecutor.schedule( () -> {
    future.cancel( true );
}, 5000L, TimeUnit.MILLISECONDS );

} catch ( InterruptedException e ) {
    log.error( "Error while emailing tradeConfirmation", e );
}

Я хочу, чтобы каждое из заданий по электронной почте обрабатывалось последовательно в одном потоке 'EmailMain', а также таймером их таймаута для запуска, когда отдельные потоки начинают их обрабатывать, а НЕ, когда задания добавляются вочередь singleThreadedExecutor. Есть ли чистое решение в Java 8? Я знаю, что в Java 9 есть несколько простых опций, подобных приведенным ниже (взято из
https://www.deadcoderising.com/java-9-handle-timeouts-asynchronously-using-completablefutures-ortimeout-and-completeontimeout/):

CompletableFuture.supplyAsync(this::getArticles)  
                 .orTimeout(1, TimeUnit.MINUTES);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...