Зарегистрируйтесь, чтобы продолжить обучение

Асинхронность Java: Продвинутое использование

В программировании часто возникает необходимость выполнять длительные операции, такие как сетевые запросы, чтение и запись файлов или взаимодействие с базами данных. В традиционном синхронном подходе, когда задачи выполняются последовательно, основной поток блокируется на каждом запросе, ожидая его завершения. Это приводит к значительному увеличению общего времени выполнения, особенно если необходимо обработать несколько запросов. Например, если три запроса занимают по 2 секунды каждый, общее время выполнения составит 6 секунд. Это может негативно сказаться на производительности и отзывчивости приложения.

Асинхронность

Асинхронность предлагает эффективный подход к решению этой проблемы. В асинхронном программировании задачи могут выполняться параллельно, что позволяет основному потоку не ждать завершения каждой операции. Вместо этого он продолжает выполнять другие задачи, пока запросы обрабатываются в фоновом режиме. Как только все запросы будут завершены, вы можете обработать результаты.

Если вы запускаете три запроса одновременно, и каждый из них занимает 2 секунды, общее время выполнения будет равно времени самого длительного запроса — 2 секунды. Это значительно сокращает время ожидания и улучшает отзывчивость приложения. Таким образом, асинхронный подход позволяет более эффективно использовать ресурсы и повышает производительность, особенно в условиях, когда необходимо обрабатывать множество длительных операций.

Класс CompletableFuture

CompletableFuture — это класс в Java, который предоставляет мощные инструменты для работы с асинхронными задачами и упрощает управление их выполнением. Он позволяет создавать цепочки асинхронных операций, обрабатывать результаты и ошибки, а также комбинировать несколько задач, что делает код более читаемым и удобным для сопровождения

Метод runAsync() в классе CompletableFuture позволяет запускать асинхронные задачи, которые не возвращают результат. Он принимает Runnable в качестве аргумента и выполняет его в отдельном потоке, что позволяет основному потоку продолжать выполнение других операций

class Example {
    public static void main(String[] args) {

        // Если нам нужно просто асинхронно выполнить задачу и не нужно ничего возвращать

        // В виде лямбды передаём объект Runnable
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            // Задержка имитирует длительно выполняющуюся задачу
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            System.out.println("Run in separate thread");
        });

        // Ожидаем окончания работы задачи
        future1.get();
    }
}

Метод supplyAsync() в классе CompletableFuture используется для запуска асинхронных задач, которые возвращают результат. Он принимает Supplier<T> в качестве аргумента, который выполняется в отдельном потоке и возвращает значение типа T. После завершения задачи, результат можно получить и обработать

class Example {
    public static void main(String[] args) {

        // Асинхронный запуск задачи и возврат результата работы

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            // Задержка имитирует длительно выполняющуюся задачу
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Result of async computation";
        });

        // Ожидаем окончания работы задачи и получаем результат
        String result = future2.get(); // "Result of async computation"
    }
}

Если нам нужно объединить результаты двух асинхронных задач, мы можем использовать метод thenCombine() класса CompletableFuture. Этот метод позволяет дождаться завершения обеих задач и применить функцию, которая объединяет их результаты в одно значение.

class Example {
    public static void main(String[] args) {

        // Комбинирование двух CompletableFuture

        // Если одна задача не зависит от другой
        // Нужно выполнить две задачи независимо одна от другой и выполнить третью,
        // когда предыдущее будут завершены


        // Задачи выполняются независимо друг от друга
        System.out.println("Retrieving weight");
        CompletableFuture<Integer> futureWeight = CompletableFuture.supplyAsync(() -> {

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
            return 100;
        });

        System.out.println("Retrieving volume");
        CompletableFuture<Integer> futureVolume = CompletableFuture.supplyAsync(() -> {

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
            return 2;
        });

        // выполняется после завершения первых двух
        System.out.println("Calculate density");
        CompletableFuture<Integer> futureDensity = futureWeight.thenCombine(futureVolume, (weight, volume) -> {
            Integer density = weight / volume;
            return density;

        // Обработка исключений
        // Если при работе задач возникли исключения
        // их можно обработать в методе exceptionally
        }).exceptionally(ex -> {
            System.out.println("Oops! We have an exception - " + ex.getMessage());
            return null;
        });
    }
}

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff