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

В чем разница между синхронной и асинхронной операцией?

2.0 Middle🔥 161 комментариев
#Многопоточность

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

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

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

Разница между синхронной и асинхронной операцией

Это фундаментальное различие в способе выполнения кода, особенно важное для веб-приложений и многопоточных систем.

Синхронная операция

Поток выполнения ждёт завершения операции:

// Синхронный вызов
String data = fetchDataFromAPI();  // Поток ждёт
System.out.println(data);          // Выполнится только после fetchDataFromAPI
processData(data);                 // И только потом выполнится это

Характеристики:

  • Поток блокируется до завершения операции
  • Проверка статуса: явная очередь операций
  • Простая модель программирования
  • Может привести к deadlock если неправильно использовать

Асинхронная операция

Операция стартует, а поток продолжает работу дальше:

// Асинхронный вызов с callback
fetchDataFromAPIAsync(data -> {
    System.out.println(data);  // Выполнится когда данные будут готовы
    processData(data);
});
System.out.println("Request started");  // Выполнится сразу

Характеристики:

  • Поток не блокируется
  • Код выполняется в другом потоке или позже
  • Обработка результата через callback/Future/Promise
  • Более сложная модель программирования

Визуальное представление

Синхронная:

Time →
Thread: [Task 1] ▯▯▯▯▯ [Task 2] ▯▯▯ [Task 3] ▯▯▯▯
        (ждёт)        (ждёт)        (выполняется)

Асинхронная:

Time →
Thread A: [Start Task 1] → [Start Task 2] → [Start Task 3] ✓
Thread B:                ▯▯▯▯▯ Task 1 выполняется
Thread C:                     ▯▯▯ Task 2 выполняется
Thread D:                          ▯▯▯▯ Task 3 выполняется

Практический пример: запрос к API

Синхронный подход:

public class SyncApiClient {
    public String fetchUser(String userId) {
        // Блокирует поток до получения ответа
        HttpResponse response = new RestTemplate()
            .getForObject("https://api/users/" + userId, String.class);
        return response;
    }
    
    public void loadUsers() {
        // Первый пользователь ждёт ~200ms
        String user1 = fetchUser("1");  // 200ms
        System.out.println(user1);
        
        // Второй пользователь ждёт ещё ~200ms
        String user2 = fetchUser("2");  // 200ms
        
        // Всего: ~400ms
    }
}

Асинхронный подход:

public class AsyncApiClient {
    private RestTemplate restTemplate;
    
    public CompletableFuture<String> fetchUserAsync(String userId) {
        return CompletableFuture.supplyAsync(() ->
            restTemplate.getForObject(
                "https://api/users/" + userId, String.class
            )
        );
    }
    
    public void loadUsersAsync() {
        // Оба запроса идут параллельно
        CompletableFuture<String> user1 = fetchUserAsync("1");
        CompletableFuture<String> user2 = fetchUserAsync("2");
        
        // Когда оба готовы, объединяем результаты
        user1.thenCombine(user2, (u1, u2) -> {
            System.out.println(u1);
            System.out.println(u2);
            return null;
        });
        
        // Всего: ~200ms вместо 400ms
    }
}

Java Future и CompletableFuture

Future (базовый асинхронный механизм):

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<String> future = executor.submit(() -> {
    Thread.sleep(1000);
    return "Result";
});

// Основной поток может делать другую работу
System.out.println("Waiting...");

// Затем получить результат
String result = future.get();  // Блокирует если результат не готов
System.out.println(result);

CompletableFuture (современный подход):

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // Выполняется в фоновом потоке
    return "Result";
});

// Цепочка асинхронных операций
future
    .thenApply(result -> result.toUpperCase())
    .thenAccept(System.out::println);

System.out.println("Main thread continues");

Обработка ошибок

Синхронная:

try {
    String data = fetchData();
    processData(data);
} catch (IOException e) {
    System.out.println("Error: " + e.getMessage());
}

Асинхронная:

fetchDataAsync()
    .thenAccept(this::processData)
    .exceptionally(error -> {
        System.out.println("Error: " + error.getMessage());
        return null;
    });

// Или через CompletableFuture
fetchDataAsync()
    .whenComplete((data, error) -> {
        if (error != null) {
            System.out.println("Error: " + error.getMessage());
        } else {
            processData(data);
        }
    });

Reactive подход (RxJava, Project Reactor)

RxJava:

Observable.fromCallable(() -> fetchDataFromAPI())
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.mainThread())
    .subscribe(
        data -> System.out.println(data),
        error -> System.out.println("Error: " + error),
        () -> System.out.println("Complete")
    );

Project Reactor (Spring WebFlux):

mono.fetch(userId)
    .doOnNext(user -> System.out.println(user))
    .doOnError(error -> System.out.println("Error: " + error))
    .subscribe();

Производительность

СценарийСинхроннаяАсинхронная
10 запросов по 100ms1000ms100ms
Простой вычисленияБыстрееМедленнее (overhead)
Блокирующие операцииНеэффективноИдеально
Малое количество задачПриемлемоОверинжиниринг

Когда использовать что

Синхронная:

  • Простые последовательные операции
  • CPU-bound задачи
  • Небольшое количество операций

Асинхронная:

  • I/O-bound операции (API, БД, файлы)
  • Высоконагруженные системы
  • Множество параллельных задач

Вывод: Синхронная операция проще для понимания, но неэффективна для I/O задач. Асинхронная операция сложнее в коде, но даёт лучшую производительность и масштабируемость при работе с сетью и БД.

В чем разница между синхронной и асинхронной операцией? | PrepBro