Назад к вопросам
Middle
229
questionbank

В чем разница между Synchronized и Lock в Java?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Synchronized - ключевое слово для обеспечения потокобезопасности. Оно может применяться к методам или блокам кода. При входе в synchronised блок или метод поток пытается получить intrinsic lock (монитор объекта). Если lock занят другим потоком, текущий поток блокируется до освобождения lock.

Преимущества Synchronized:

  • Простота использования.
  • Автоматическое освобождение lock при выходе из synchronised блока (даже при исключениях).

Недостатки Synchronized:

  • Негибкий: нельзя получить lock неблокирующим способом, нельзя прерывать ожидание lock, нельзя иметь multiple read locks.
  • Сложно реализовать более сложные сценарии синхронизации, такие как тайм-аут ожидания lock или несправедливый порядок захвата lock.

Пример Synchronized:

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

Lock - это интерфейс и набор классов в пакете java.util.concurrent.locks, предоставляющий более гибкие возможности управления блокировками. Основной класс - ReentrantLock.

Преимущества Lock:

  • Большая гибкость: можно получить lock неблокирующим способом (tryLock()), можно прерывать ожидание lock (lockInterruptibly()), можно иметь разные типы lock (например, ReadWriteLock).
  • Можно управлять справедливостью захвата lock (справедливый/несправедливый режим - ReentrantLock(boolean fair)).
  • Возможность получить информацию о блокировке (например, isLocked()).

Недостатки Lock:

  • Более сложный в использовании: необходимо явно вызывать lock() и unlock(). Обязательно использовать блок finally для освобождения lock, чтобы избежать deadlock в случае исключения.

Пример Lock:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class SafeCounter implements Counter {
    private int count = 0;
    private final Lock lock = new ReentrantLock();

    @Override
    public void increment() {
        lock.lock(); // Захват блокировки
        try {
            count++;
        } finally {
            lock.unlock(); // Освобождение блокировки обязательно в finally
        }
    }

    @Override
    public int getCount() {
        lock.lock(); // Захват блокировки
        try {
            return count;
        } finally {
            lock.unlock(); // Освобождение блокировки
        }
    }
}

Ключевые различия summarized:

Аспект Synchronized Lock (ReentrantLock)
Тип Ключевое слово Интерфейс и классы (API)
Применение Методы, блоки кода Объекты Lock
Гибкость Меньшая Большая
Функции Базовая синхронизация Неблокирующий захват, прерывание ожидания, тайм-аут, разные типы lock
Освобождение Автоматическое (при выходе) Ручное (необходимо unlock(), обычно в finally)
Справедливость Нельзя настроить (несправедливый) Можно настроить

В общем случае, synchronized подходит для простых случаев синхронизации, где достаточно эксклюзивного доступа. Lock предпочтителен при необходимости большей гибкости и контроля над процессом блокировки, а также при реализации более сложных стратегий параллельного доступа (например, используя ReadWriteLock).