Что такое синхронизация потоков (thread synchronization) в Java?

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

Ответ

Синхронизация потоков — это механизм координации доступа нескольких потоков к общим ресурсам (переменным, объектам, файлам) для предотвращения состояний гонки (race condition) и обеспечения согласованности данных.

Без синхронизации параллельные операции чтения/записи могут привести к потере обновлений, чтению некорректных промежуточных состояний или другим недетерминированным ошибкам.

Основные механизмы синхронизации в Java:

  1. Ключевое слово synchronized (монитор объекта/класса):

    public class SynchronizedCounter {
        private int count = 0;
    
        // Синхронизированный метод (монитор — this)
        public synchronized void increment() {
            count++; // Операция "чтение-изменение-запись" теперь атомарна
        }
    
        // Синхронизированный блок
        public void decrement() {
            synchronized (this) { // Явное указание монитора
                count--;
            }
        }
    }
  2. Блокировки из пакета java.util.concurrent.locks (более гибкие):

    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockCounter {
        private int count = 0;
        private final ReentrantLock lock = new ReentrantLock();
    
        public void increment() {
            lock.lock(); // Захватываем блокировку
            try {
                count++;
            } finally {
                lock.unlock(); // Всегда освобождаем в finally!
            }
        }
    }
  3. Атомарные классы (java.util.concurrent.atomic) для простых операций:

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class AtomicCounter {
        private AtomicInteger count = new AtomicInteger(0);
    
        public void increment() {
            count.incrementAndGet(); // Атомарная операция без явных блокировок
        }
    }

Ключевые концепции:

  • Взаимное исключение (Mutual Exclusion): Только один поток может выполнять критическую секцию.
  • Видимость (Visibility): Изменения, сделанные одним потоком в синхронизированном блоке, гарантированно видны другому потоку, входящему в синхронизированный блок по тому же монитору (решается через отношение happens-before).

Важно: Синхронизация может приводить к взаимным блокировкам (deadlock) и снижению производительности, поэтому ее следует применять минимально и обдуманно.