Многопоточность

Тема дорожной карты · Java

Java Concurrency — это дисциплина проектирования программ, выполняющих множество задач одновременно с использованием потоков, процессов и высокоуровневых примитивов координации из пакета java.util.concurrent. JVM отображает Java-потоки на потоки ОС (или, с Project Loom, на лёгкие virtual threads), а Java Memory Model (JMM) определяет гарантии видимости между потоками — поля volatile обеспечивают видимость без взаимного исключения, тогда как блоки и методы synchronized используют встроенный монитор объекта для обеспечения как видимости, так и атомарности. Пакет java.util.concurrent, введённый в Java 5, предоставляет высокоуровневые примитивы, заменяющие прямое использование synchronized: ReentrantLock, ReadWriteLock, Semaphore, CountDownLatch, CyclicBarrier и Phaser охватывают большинство паттернов координации, а атомарные классы AtomicInteger, AtomicLong и AtomicReference реализуют неблокирующие операции compare-and-swap (CAS). Распространённые опасности Java Concurrency включают гонки данных (несинхронизированные чтения и записи общего состояния), взаимоблокировки (два потока, ожидающих блокировок друг друга), живые блокировки и голодание — инструменты профилирования JVM и фреймворки вроде JCStress используются для обнаружения этих ошибок. Владение Java Concurrency является обязательным условием для работы с Java Executor Framework, CompletableFuture, Concurrent Collections и virtual threads Project Loom, добавленными в Java 21 как стабильная функция.

Как это работает

Многопоточность имеет много инструментов: Thread (низкоуровневый), Executor / ExecutorService (пулы потоков), CompletableFuture (async-композиция), Future, java.util.concurrent коллекции (ConcurrentHashMap, BlockingQueue, CopyOnWriteArrayList), атомарные примитивы (AtomicInteger, AtomicReference). Java 21 даёт virtual threads (Project Loom — миллионы лёгких потоков, идеально для I/O-bound). Синхронизация: synchronized, ReentrantLock, ReadWriteLock, StampedLock. Memory model (JMM) управляет видимостью.

Когда применять

ExecutorService вместо сырых Thread — пулы управляют жизненным циклом. CompletableFuture — для async-композиции (thenApply, thenCompose, allOf). На Java 21+ virtual threads делают блокирующий I/O практичным на высокой конкурентности (Executors.newVirtualThreadPerTaskExecutor()). ConcurrentHashMap — для shared-state. Прочтите "Java Concurrency in Practice" до серьёзного concurrent-кода.

Типичные ошибки

Ловушки Многопоточность: shared mutable state без синхронизации (visibility-баги); volatile-"фикс" для race, требующих атомарности (volatile только видимость, не атомарный RMW); deadlock из-за двух локов в разном порядке; не daemon-threads когда нужно (JVM висит при shutdown); слишком много потоков для I/O-bound до Loom (новый ответ — virtual threads).

Связанные понятия

Полезные ресурсы