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

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

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

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

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

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

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

Эти два понятия часто путают, но они обозначают разные вещи. Давайте разберёмся с примерами.

Определения

Параллелизм (Parallelism) — это одновременное выполнение нескольких задач на разных ядрах процессора. Это физическое явление — задачи действительно выполняются в один и тот же момент времени.

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

Аналогия: ресторан

Параллелизм:

Повар 1 готовит блюдо A
Повар 2 готовит блюдо B
Повар 3 готовит блюдо C

Время: ████████████ (все готовят одновременно на разных плитах)

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

Один повар:
1. Начинает готовить блюдо A (поставить в духовку)
2. Не ждёт, начинает готовить блюдо B (пока A готовится)
3. Не ждёт, начинает готовить блюдо C
4. Блюдо A готово → берёт его
5. Продолжает готовить D

Время: ████ (один повар, но переключается между задачами)

В Java код

Параллелизм (использование многопоточности на мультиядерном CPU):

public class ParallelismExample {
    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        
        // Задача 1 в потоке 1
        Thread thread1 = new Thread(() -> {
            System.out.println("Поток 1 начал работу");
            try { Thread.sleep(2000); } catch (InterruptedException e) {}
            System.out.println("Поток 1 завершил работу");
        });
        
        // Задача 2 в потоке 2
        Thread thread2 = new Thread(() -> {
            System.out.println("Поток 2 начал работу");
            try { Thread.sleep(2000); } catch (InterruptedException e) {}
            System.out.println("Поток 2 завершил работу");
        });
        
        // На 2-ядерном CPU оба потока выполняются параллельно
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("Время: " + elapsed + "ms");
        // ~2000ms (параллельно), а не 4000ms (последовательно)
    }
}

// Вывод:
// Поток 1 начал работу
// Поток 2 начал работу
// Поток 1 завершил работу
// Поток 2 завершил работу
// Время: ~2000ms

Асинхронность (CompletableFuture в одном потоке):

public class AsynchronousExample {
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        
        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Задача 1 начала работу");
            try { Thread.sleep(2000); } catch (InterruptedException e) {}
            System.out.println("Задача 1 завершена");
            return "Результат 1";
        });
        
        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Задача 2 начала работу");
            try { Thread.sleep(2000); } catch (InterruptedException e) {}
            System.out.println("Задача 2 завершена");
            return "Результат 2";
        });
        
        // Ждём завершения обеих задач
        CompletableFuture.allOf(task1, task2).join();
        
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("Время: " + elapsed + "ms");
        // ~2000ms (асинхронно)
    }
}

Основные различия

АспектПараллелизмАсинхронность
Ядра CPUРазные ядраОдно ядро (или пул)
ВыполнениеОдновременноЧередование
БлокировкаМожет бытьНе блокирует
СложностьВыше (синхронизация)Ниже (callbаcks)
МасштабируемостьОграничена ядрамиБольшие числа
ПрименениеCPU-bound задачиI/O-bound задачи

Пример 1: Асинхронность на одном ядре (I/O операции)

public class IoAsyncExample {
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        
        // Асинхронная загрузка файлов
        CompletableFuture<String> file1 = CompletableFuture.supplyAsync(() -> 
            readFile("file1.txt")  // блокирующая операция
        );
        
        CompletableFuture<String> file2 = CompletableFuture.supplyAsync(() -> 
            readFile("file2.txt")
        );
        
        CompletableFuture<String> file3 = CompletableFuture.supplyAsync(() -> 
            readFile("file3.txt")
        );
        
        // Загружаются "асинхронно" (на самом деле в пуле потоков)
        CompletableFuture.allOf(file1, file2, file3).join();
        
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("Время: " + elapsed + "ms");
        // ~time(file1) если параллельно на разных потоках
    }
    
    private static String readFile(String filename) {
        // Блокирующая I/O операция
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        return "Content of " + filename;
    }
}

Пример 2: Параллелизм (CPU-bound задачи)

public class ParallelProcessingExample {
    public static void main(String[] args) throws Exception {
        // CPU-bound вычисления на разных ядрах
        long start = System.currentTimeMillis();
        
        int[] data = new int[100000000];
        
        // Последовательно (медленно)
        long sum1 = 0;
        for (int i = 0; i < data.length; i++) {
            sum1 += data[i];
        }
        
        // Параллельно (быстро на мультиядерном CPU)
        long sum2 = java.util.Arrays.stream(data)
            .parallel()  // разбить на части, обработать на разных ядрах
            .sum();
        
        System.out.println("Sequence: " + (System.currentTimeMillis() - start) + "ms");
        System.out.println("Parallel: " + (System.currentTimeMillis() - start) + "ms");
    }
}

// Parallel версия значительно быстрее на многоядерных CPU

Пример 3: Асинхронное программирование (CompletableFuture)

public class AsyncProgrammingExample {
    public static void main(String[] args) throws Exception {
        // Цепочка асинхронных операций
        CompletableFuture.supplyAsync(() -> fetchUserData(1))
            .thenApply(user -> fetchUserPosts(user.getId()))
            .thenApply(posts -> filterPosts(posts))
            .thenAccept(filtered -> System.out.println("Результат: " + filtered))
            .join();
    }
    
    static class User { int id; }
    static class Post { int id; }
    
    private static User fetchUserData(int userId) {
        System.out.println("Загружаю пользователя...");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        return new User();
    }
    
    private static java.util.List<Post> fetchUserPosts(int userId) {
        System.out.println("Загружаю посты...");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        return new java.util.ArrayList<>();
    }
    
    private static java.util.List<Post> filterPosts(java.util.List<Post> posts) {
        System.out.println("Фильтрую посты...");
        return posts;
    }
}

Пример 4: Реактивное программирование

import java.util.concurrent.CompletableFuture;

public class ReactiveExample {
    public static void main(String[] args) throws Exception {
        // Асинхронное слушание событий
        CompletableFuture<String> event = new CompletableFuture<>();
        
        // Слушатель (не блокирует)
        event.thenAccept(data -> System.out.println("Получено: " + data));
        
        // Отправитель (в другом потоке)
        new Thread(() -> {
            try { Thread.sleep(2000); } catch (InterruptedException e) {}
            event.complete("Данные готовы!");
        }).start();
        
        System.out.println("Main не заблокирован");
        // Продолжает работу, не ждя завершения
    }
}

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

Параллелизм используй для:

  • CPU-bound задачи (вычисления, обработка данных)
  • Задачи требуют мощности CPU
  • Пример: parallel streams, ForkJoinPool

Асинхронность используй для:

  • I/O-bound операции (сеть, файлы, БД)
  • Большое количество одновременных операций
  • Отзывчивый UI (не блокировать главный поток)
  • Пример: CompletableFuture, callbacks, reactive streams

Комбинация: Параллелизм + Асинхронность

public class HybridExample {
    public static void main(String[] args) throws Exception {
        // Асинхронно загружаем данные
        CompletableFuture<int[]> dataFuture = CompletableFuture.supplyAsync(() -> 
            loadDataFromNetwork()  // I/O операция
        );
        
        // Когда данные готовы, обрабатываем параллельно
        CompletableFuture<Long> result = dataFuture.thenApply(data ->
            java.util.Arrays.stream(data)
                .parallel()  // CPU-bound обработка
                .sum()
        );
        
        Long sum = result.join();
        System.out.println("Сумма: " + sum);
    }
    
    private static int[] loadDataFromNetwork() {
        // I/O операция
        try { Thread.sleep(2000); } catch (InterruptedException e) {}
        return new int[1000000];
    }
}

Вывод

Параллелизм:

  • Физическое одновременное выполнение на разных ядрах
  • Для CPU-bound задач
  • Требует синхронизации

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

  • Логическое чередование выполнения
  • Для I/O-bound задач
  • Позволяет одному потоку обрабатывать множество задач

В Java:

  • Параллелизм: Thread, ExecutorService, ForkJoinPool, .parallel()
  • Асинхронность: CompletableFuture, callbacks, reactive streams (Project Reactor, RxJava)

Оба подхода могут использоваться вместе для максимальной эффективности.

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