Какие способы реализации ожидания ответа существуют в Java?

«Какие способы реализации ожидания ответа существуют в Java?» — вопрос из категории Сети, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Java ожидание ответа или завершения операции можно реализовать несколькими способами, выбор зависит от контекста: многопоточность, асинхронность или тестирование.

Основные подходы:

  1. Thread.sleep() — простейшая блокировка потока на указанное время. Не рекомендуется для production-кода, так как поток бесполезно занят.

    Thread.sleep(1000); // Поток блокируется на 1 секунду
  2. wait() / notify() — механизм ожидания по условию в рамках синхронизированного блока.

    synchronized (lockObject) {
        while (!conditionMet) {
            lockObject.wait(); // Освобождает монитор и ждет notify()
        }
        // Условие выполнено, продолжаем работу
    }
  3. Future и CompletableFuture — для асинхронных вычислений. Метод get() блокирует поток до получения результата.

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        return longRunningOperation();
    });
    String result = future.get(); // Блокирующее ожидание
  4. CountDownLatch, CyclicBarrier, Semaphore — высокоуровневые синхронизаторы из java.util.concurrent для координации потоков.

    CountDownLatch latch = new CountDownLatch(1);
    // В другом потоке после выполнения задачи:
    latch.countDown();
    // Ожидание в основном потоке:
    latch.await();

Для тестирования удобно использовать библиотеку Awaitility, которая позволяет декларативно описывать ожидания.

await().atMost(5, SECONDS).until(() -> service.isReady());

Рекомендация: В production-коде предпочтительны асинхронные подходы (CompletableFuture, реактивные стримы) или специализированные синхронизаторы, чтобы избежать бесполезной блокировки потоков.