← Назад к вопросам

Что такое асинхронное программирование?

1.7 Middle🔥 161 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Асинхронное программирование

Асинхронное программирование — это подход, при котором код может начать долгоживущую операцию и продолжить выполнение без ожидания её завершения. Результат операции обрабатывается позже через callbacks, futures или promises.

Основная идея

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

// Синхронный код (блокирующий)
String result = fetchDataFromServer(); // Программа ждёт здесь
System.out.println(result);

В асинхронном программировании программа начинает операцию и продолжает выполнение:

// Асинхронный код (неблокирующий)
fetchDataFromServerAsync()
    .thenAccept(result -> System.out.println(result))
    .thenApply(data -> parseData(data))
    .exceptionally(ex -> handleError(ex));

Проблема синхронизма

В веб-приложениях часто нужно работать с I/O операциями (базы данных, внешние API, файловая система). Синхронный код создаёт проблемы:

// Плохо: один поток на каждого пользователя
public void handleRequest() {
    String userData = queryDatabase(); // Ждёт 200ms
    String externalData = callAPI();   // Ждёт 500ms
    // В это время поток ничего не делает, зря занимает ресурсы
}

Для 1000 пользователей нужно 1000 потоков, что очень дорого.

Асинхронное решение

// Хорошо: один поток обслуживает множество пользователей
public void handleRequestAsync() {
    queryDatabaseAsync() // Не блокирует
        .thenCompose(userData -> callAPIAsync(userData))
        .thenAccept(result -> sendResponse(result));
    // Поток свободен, может обслуживать других пользователей
}

Способы асинхронного программирования в Java

1. Callbacks (обратные вызовы)

// Callback-интерфейс
interface DataCallback {
    void onSuccess(String data);
    void onError(Exception error);
}

// Асинхронный метод
public void fetchDataAsync(DataCallback callback) {
    new Thread(() -> {
        try {
            String data = fetchFromServer();
            callback.onSuccess(data);
        } catch (Exception e) {
            callback.onError(e);
        }
    }).start();
}

// Использование
fetchDataAsync(new DataCallback() {
    @Override
    public void onSuccess(String data) {
        System.out.println("Данные: " + data);
    }
    
    @Override
    public void onError(Exception error) {
        System.err.println("Ошибка: " + error);
    }
});

Проблема Callback Hell: При вложении callbacks код становится нечитаемым.

2. Future и CompletableFuture

// CompletableFuture — более удобный способ
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return fetchFromServer();
});

// Обработка результата
future
    .thenApply(data -> data.toUpperCase())
    .thenAccept(result -> System.out.println(result))
    .exceptionally(ex -> {
        System.err.println("Ошибка: " + ex);
        return null;
    });

// Цепочка асинхронных операций
CompletableFuture<String> result = 
    getUserAsync(userId)
        .thenCompose(user -> getOrdersAsync(user.getId()))
        .thenCompose(orders -> getDetailsAsync(orders))
        .thenApply(details -> formatResult(details));

3. Reactive Programming (RxJava, Project Reactor)

// RxJava пример
Observable.fromCallable(() -> fetchFromServer())
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        data -> System.out.println("Результат: " + data),
        error -> System.err.println("Ошибка: " + error)
    );

4. Виртуальные потоки (Virtual Threads, Java 21+)

// Новый подход: виртуальные потоки
// Возвращает асинхронность, но с синхронным кодом
var executor = Executors.newVirtualThreadPerTaskExecutor();

executor.execute(() -> {
    String data = fetchDataFromServer(); // Выглядит синхронно
    System.out.println(data);
});

Преимущества асинхронного программирования

  • Масштабируемость: Один поток может обслуживать тысячи операций
  • Высокая пропускная способность: Лучшее использование ресурсов
  • Отзывчивость: UI не замораживается
  • Эффективность: Меньше потребление памяти

Недостатки

  • Сложность: Асинхронный код труднее писать и отлаживать
  • Ошибки: Ошибки в callbacks труднее отловить
  • Stack traces: Менее информативные сообщения об ошибках

Практический пример: Spring Boot

@Service
public class UserService {
    @Autowired
    private RestTemplate restTemplate;
    
    // Асинхронный метод
    @Async
    public CompletableFuture<User> getUserAsync(Long id) {
        return CompletableFuture.supplyAsync(() -> {
            return fetchUserFromDatabase(id);
        });
    }
}

@RestController
public class UserController {
    @Autowired
    private UserService userService;
    
    @GetMapping("/users/{id}")
    public CompletableFuture<ResponseEntity<User>> getUser(@PathVariable Long id) {
        return userService.getUserAsync(id)
            .thenApply(ResponseEntity::ok)
            .exceptionally(ex -> ResponseEntity.status(500).build());
    }
}

Асинхронное программирование — неотъемлемая часть современной разработки, особенно в веб-приложениях и микросервисах.

Что такое асинхронное программирование? | PrepBro