Каковы основы работы с многопоточностью (Multithreading) в Java?

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

Ответ

Многопоточность в Java — это выполнение нескольких потоков (threads) внутри одного процесса для параллельной или конкурентной обработки задач.

1. Создание и запуск потока:

  • Через Runnable (предпочтительнее):
    Runnable task = () -> {
        System.out.println("Выполняется в потоке: " + Thread.currentThread().getName());
    };
    Thread thread = new Thread(task);
    thread.start(); // Важно: start(), а не run()
  • Через наследование Thread:
    class MyThread extends Thread {
        @Override
        public void run() { /* логика */ }
    }
    new MyThread().start();

2. Синхронизация и безопасность потоков:

  • Ключевое слово synchronized:

    public synchronized void method() { /* ... */ } // Синхронизация по экземпляру (this)
    
    synchronized (lockObject) { // Синхронизация по произвольному объекту
        // критическая секция
    }
  • Использование атомарных классов (java.util.concurrent.atomic):
    AtomicInteger counter = new AtomicInteger(0);
    counter.incrementAndGet(); // Атомарная операция
  • Ключевое слово volatile: Гарантирует видимость изменений переменной для всех потоков (но не атомарность составных операций).

3. Управление пулами потоков (ExecutorService):

ExecutorService executor = Executors.newFixedThreadPool(4); // Пул из 4 потоков
for (int i = 0; i < 10; i++) {
    executor.submit(() -> System.out.println("Task " + i));
}
executor.shutdown(); // Остановка после выполнения всех задач

4. Потокобезопасные коллекции: Используйте их вместо ручной синхронизации.

  • ConcurrentHashMap
  • CopyOnWriteArrayList
  • BlockingQueue (например, ArrayBlockingQueue)

5. Распространённые проблемы:

  • Состояние гонки (Race Condition): Несогласованный доступ к общим данным.
  • Взаимная блокировка (Deadlock): Два или более потока бесконечно ждут друг друга.
  • Голодание (Starvation): Поток не получает доступа к ресурсам.

Современный подход: Для асинхронных вычислений и композиции задач используйте CompletableFuture (Java 8+).