Какие инструменты многопоточности используются в Java и для чего?

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

Ответ

Java предоставляет несколько уровней абстракции для работы с многопоточностью:

1. Базовые механизмы:

  • Thread, Runnable — низкоуровневое создание потоков (используется редко напрямую).

2. Управление пулами потоков (java.util.concurrent):

  • ExecutorService — основной интерфейс для управления пулами.
    ExecutorService executor = Executors.newFixedThreadPool(4);
    Future<Integer> future = executor.submit(() -> {
    // Долгая задача
    return 42;
    });
    Integer result = future.get(); // Блокирующее получение результата
    executor.shutdown();
  • ThreadPoolExecutor — для тонкой настройки пула (размер, очередь).

3. Асинхронные вычисления с результатом:

  • CompletableFuture (Java 8+) — для построения асинхронных цепочек без блокировки.
    CompletableFuture.supplyAsync(() -> fetchData(), executor)
    .thenApply(data -> process(data))
    .thenAccept(result -> System.out.println(result));

4. Параллельные коллекции и стримы:

  • ConcurrentHashMap, CopyOnWriteArrayList — потокобезопасные коллекции.
  • collection.parallelStream() — параллельная обработка данных.

5. Синхронизация и атомарность:

  • synchronized — ключевое слово для блокировок.
  • Lock, ReentrantLock — более гибкие блокировки.
  • AtomicInteger, AtomicReference — атомарные операции без блокировок.

Проблемы и решения:

  • Race Condition → Синхронизация, атомарные классы.
  • Deadlock → Упорядоченное захватывание блокировок.
  • Производительность → Использование пулов и неблокирующих алгоритмов (CAS).