Чтобы асинхронно отправлять большие электронные письма с фиксированной скоростью, я использую ScheduledExecutorService.
У меня есть класс, реализующий Runnable, который асинхронно отправляет почту. Его нужно вызывать каждую секунду и ровно x раз. Для фактической отправки я использую Простая почта Java. Я вызываю метод EmailBuilder#send(mail, /* boolean async */ true).
После того, как этот метод был вызван эти x раз, вызывается ScheduledExecutorService#shutdown().
Я бы хотел определить, в какой момент времени все запланированные Runnables завершились, то есть все вызовы EmailBuilder#send(mail, /* boolean async */ true) вернулись.
Я попробовал ScheduledExecutorService#awaitTermination() с некоторым таймаутом, а также ScheduledFuture#get(), но это не сработало или возникло какое-то исключение.
package playground;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.simplejavamail.email.Email;
import org.simplejavamail.email.EmailBuilder;
import org.simplejavamail.mailer.Mailer;
import org.simplejavamail.mailer.MailerBuilder;
public class MCVE {
private ScheduledExecutorService scheduler;
private SendTask sd;
private ScheduledFuture<?> sf;
private boolean terminateFlag = false;
public void start() {
sd = new SendTask();
scheduler = Executors.newSingleThreadScheduledExecutor();
sf = scheduler.scheduleAtFixedRate(sd, 0, 1, TimeUnit.SECONDS);
}
private class SendTask implements Runnable {
@Override
public void run() {
Mailer mailer = MailerBuilder.withSMTPServer("smtp.gogglemail.com", 587).buildMailer();
Email mail = EmailBuilder.startingBlank()
.from("[email protected]")
.to("[email protected]")
.withSubject("Subject")
.withPlainText("Content")
.buildEmail();
mailer.sendMail(mail, /* async */ true);
if (terminateFlag) {
sf.cancel(true);
scheduler.shutdown();
return;
}
}
}
}
Спасибо за полезный совет!




Соберите все фьючерсы, возвращенные после планирования, в коллекции, а затем выполните foreach get ().
ScheduledExecutorService#scheduleAtFixedRate() возвращает только один ScheduledFuture. Вызов get() бросает CancellationException.
Если вы планируете с фиксированной скоростью, когда вы ожидаете, что все задачи будут выполнены ?, это будет повторяться вечность.
Нет, поскольку ScheduledExecutorService выключен, выполнение программы будет прекращено.
А как насчет sf.isCancelled ()? Это не то, что вы ищете?
Нет, потому что ScheduledFuture#cancel() вызывается после начала отправки всех писем, но поскольку они отправляются асинхронно, неясно, действительно ли процесс отправки завершен. Таким образом, ScheduledFuture#isCancelled() вернет true до того, как все письма будут отправлены (полностью), если отправка занимает больше времени, чем период / скорость, переданные ScheduledExecutorService#scheduleAtFixedRate().
Ваш SendTask уже асинхронно вызван из вашей основной программы. Почему вы вызываете async почтовой программы, а затем хотите узнать, когда она завершится? Вы можете выполнить синхронизацию этого вызова, удалить завершенную часть и использовать метод, предложенный @Eddie.
Вам действительно нужно добавить код, желательно минимальный воспроизводимый пример.