В чем разница между параллелизмом и асинхронностью?

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

Ответ

Асинхронность и параллелизм — это связанные, но разные концепции.

Аспект Асинхронность (Asynchrony) Параллелизм (Concurrency)
Цель Освободить текущий поток от ожидания, особенно при блокирующих I/O операциях. Выполнять несколько задач одновременно, используя несколько ядер CPU.
Фокус Управление потоком выполнения, неблокирующие операции. Одновременное выполнение множества задач.
Реализация в Java CompletableFuture, обратные вызовы (callbacks), реактивные потоки (Mono/Flux). ForkJoinPool, parallelStream(), запуск нескольких Thread.
Отношение к потокам Может использовать один поток для кооперативной многозадачности (например, цикл событий). Требует нескольких потоков или процессов.

Ключевое отличие: Асинхронная задача может выполняться в одном потоке, переключая контекст, в то время как параллельная задача требует нескольких потоков.

Примеры:

  1. Асинхронный, но не параллельный (один поток):

    // Реактивный подход: множество асинхронных запросов могут обрабатываться одним потоком-событий
    Flux.range(1, 1000)
        .flatMap(id -> WebClient.get().uri("/item/{id}", id).retrieve().bodyToMono(Item.class))
        .subscribe(); // Неблокирующие HTTP-вызовы
  2. Параллельный (много потоков):

    // Параллельная обработка CPU-интенсивной задачи
    List<Result> results = dataList.parallelStream() // Использует ForkJoinPool.commonPool()
                                   .map(data -> cpuIntensiveCalculation(data))
                                   .collect(Collectors.toList());
  3. Асинхронный и параллельный:

    // Несколько асинхронных задач, выполняемых в разных потоках пула
    List<CompletableFuture<String>> futures = urlList.stream()
        .map(url -> CompletableFuture.supplyAsync(() -> fetchUrl(url), httpClientExecutor))
        .collect(Collectors.toList());
    
    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

Практическое применение:

  • Асинхронность: Веб-серверы (обработка тысяч одновременных соединений), клиенты БД/HTTP.
  • Параллелизм: Обработка больших наборов данных, математические вычисления.