Что такое пакет java.util.concurrent в Java?

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

Ответ

java.util.concurrent (JUC) — это стандартный пакет Java, предоставляющий высокоуровневые, надежные и производительные инструменты для разработки параллельных (многопоточных) приложений. Он был введен в Java 5 для решения сложностей и ошибок, связанных с ручным управлением потоками и низкоуровневой синхронизацией.

Основные компоненты пакета:

  1. Executor Framework: Абстракция для управления пулами потоков.

    • Executor, ExecutorService, ScheduledExecutorService.
    • Фабрики Executors (например, newFixedThreadPool, newCachedThreadPool).
  2. Потокобезопасные коллекции (Concurrent Collections): Коллекции, оптимизированные для многопоточного доступа без внешней синхронизации.

    • ConcurrentHashMap, CopyOnWriteArrayList, BlockingQueue.
  3. Синхронизаторы (Synchronizers): Утилиты для координации работы потоков.

    • CountDownLatch — ожидание завершения набора операций.
    • CyclicBarrier — точка сбора для группы потоков.
    • Semaphore — контроль доступа к ограниченному ресурсу.
    • Exchanger — обмен данными между двумя потоками.
  4. Атомарные переменные (Atomic Variables): Классы для атомарных операций над одиночными переменными без использования блокировок (на основе compare-and-swap).

    • AtomicInteger, AtomicLong, AtomicReference.
  5. Усовершенствованные механизмы блокировок (Locks): Более гибкая альтернатива ключевому слову synchronized.

    • ReentrantLock, ReentrantReadWriteLock.
    • Condition — аналог методов wait()/notify() для Lock.

Пример использования ExecutorService:

import java.util.concurrent.*;

public class ExecutorExample {
    public static void main(String[] args) {
        // Создаем пул из 2 потоков
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // Отправляем задачи на выполнение
        executor.submit(() -> {
            String threadName = Thread.currentThread().getName();
            System.out.println("Task 1 executed by " + threadName);
        });
        executor.submit(() -> {
            String threadName = Thread.currentThread().getName();
            System.out.println("Task 2 executed by " + threadName);
        });

        // Инициируем упорядоченное завершение (не принимаем новые задачи)
        executor.shutdown();
        try {
            // Ожидаем завершения всех задач (но не более 10 секунд)
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                executor.shutdownNow(); // Принудительное завершение
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}

Преимущества использования JUC: повышение производительности, уменьшение сложности кода, снижение вероятности ошибок (deadlock, race condition) по сравнению с ручным управлением потоками.