Java Multi-Threading. Можно ли завершать поток и получать значение по условию, а в противном случае повторять вызов?
Название может сбить с толку, потому что вопрос не тривиальный и я не могу кратко его описать.
Представим есть класс имитирующий ответ от микросервиса:
public class MicroserviceCallEmulator implements CallEmulator {
private static final List<String> VALUES = Arrays.asList("A", "B", "C");
@Override
public String doCall() {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
} catch (InterruptedException e) { throw new RuntimeException(e); }
return VALUES.get(ThreadLocalRandom.current().nextInt(3));
}
}
В нём есть метод doCall(), который имитирует задержку а потом возвращает одно из значений списка VALUES. И есть класс использующий этот имитатор:
public class MicroserviceCallProvoker implements CallProvoker {
private final CallEmulator callEmulator;
public MicroserviceCallProvoker(CallEmulator callEmulator) {
this.callEmulator = callEmulator;
}
@Override
public void doSomething() {
callEmulator.doCall();
}
}
В методе doSomething() нужно реализовать следующую логику:
- Вызов
doCall()должен быть асинхронным. То естьdoSomething()должен просто отправлять запрос и ничего не ждать и не возвращать. - Значения
AиBответе отdoCall()являются не подходящими. Вызовы нужно продолжать асинхронно до тех пор, пока отdoCall()не вернётьсяC - Вызовы
doCall()после непдоходящего ответа необходимо повторно посылать НЕ сразу же, а по истечению 10 секунд - Есть предел по времени. Повторные вызовы
doCall()должны быть ограничены по времени. К примеру,doCall()может 1000 раз вернуть строкуAи это займёт 1000 секунд. Такое поведение не подходит. Мы должны пытаться вызывать его в течении 400 секунд и потом (даже если не получили заветную строкуC) прекращать выполнение асинхронной задачи.
Не подумайте, я не прошу Вас решать какую-то задачу. Это - реальная проблема с которой я столкнулся и я не могу понять какими средствами Java можно реализовать столь сложную цепь, если это вообще возможно. Асинхронно пульнуть задачу не трудно, но как это повторять до подходящего условия и ограничить такое повторение по времени?
Ответы (1 шт):
Сначала всю логику повтороных попыток реализовываем в отдельной функции:
void doCallWithRetry() {
long endTime = System.currentTimeMillis() +
TimeUnit.MILLISECONDS.convert(400, TimeUnit.SECONDS);
while (System.currentTimeMillis() <= endTime) {
String result = callEmulator.doCall();
if (result.equal("C")) {
break;
}
TimeUnit.SECONDS.sleep(10);
}
}
И теперь запускаем doCallWithRetry в отдельном потоке из doSomething (в примере использую ExecutorService, но можно любой другой способ запуска в отдельном потоке):
void doSomething() {
executorService.execute(this::doCallWithRetry);
}