Как ограничить время выполнения задачи
Короткий ответ
Future.get() с тайм-аутом ждёт не дольше указанного времени и выбрасывает TimeoutException:
void main() throws Exception {
try (var pool = Executors.newSingleThreadExecutor()) {
Future<String> future = pool.submit(() -> {
Thread.sleep(2000);
return "report";
});
try {
IO.println(future.get(300, TimeUnit.MILLISECONDS));
} catch (TimeoutException e) {
future.cancel(true);
IO.println("Too slow, cancelled: " + future.isCancelled());
}
}
}Результат:
Too slow, cancelled: truecancel(true) прерывает поток задачи, иначе пул ждал бы её завершения при закрытии.
Значение по умолчанию
completeOnTimeout() подставляет значение, если задача не успела:
void main() {
String result = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "fresh data";
})
.completeOnTimeout("cached data", 200, TimeUnit.MILLISECONDS)
.join();
IO.println(result);
}Результат:
cached dataОшибка по тайм-ауту
orTimeout() завершает задачу с TimeoutException:
void main() {
var future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return 42;
}).orTimeout(200, TimeUnit.MILLISECONDS);
try {
future.join();
} catch (CompletionException e) {
IO.println(e.getCause().getClass().getSimpleName());
}
}Результат:
TimeoutExceptionЧастая ошибка
Вызывать get() без тайм-аута для задач, которые ходят в сеть. Если сервер не ответит, программа будет ждать вечно. Ставьте ограничение и на саму операцию (например, тайм-аут у HTTP-клиента), и на ожидание результата.
Функции из этого ответа
- Future.get() — Ждёт завершения задачи и возвращает её результат.
- CompletableFuture.supplyAsync() — Запускает вычисление асинхронно и возвращает `CompletableFuture`.