В чём преимущество интерфейса Lock над synchronized в Java?

Ответ

Интерфейс java.util.concurrent.locks.Lock (и его реализация ReentrantLock) предоставляет более гибкий и расширенный контроль над синхронизацией по сравнению с ключевым словом synchronized.

Основные преимущества Lock:

  1. Возможность попытки захвата блокировки:

    Lock lock = new ReentrantLock();
    if (lock.tryLock(2, TimeUnit.SECONDS)) { // Ждём не более 2 секунд
        try {
            // Критическая секция
        } finally {
            lock.unlock();
        }
    } else {
        // Действие, если блокировка не получена
    }
  2. Прерываемое ожидание: Метод lockInterruptibly() позволяет прервать поток, ожидающий блокировку.

  3. Честность (Fairness): ReentrantLock можно создать с политикой честности, что уменьшает вероятность голодания потоков.

  4. Разделение на чтение/запись: ReentrantReadWriteLock позволяет множеству потоков читать данные одновременно, но блокирует их на время записи, что повышает производительность.

Стандартный шаблон использования:

Lock lock = new ReentrantLock();
// ...
lock.lock(); // Всегда перед try
try {
    // Критическая секция
} finally {
    lock.unlock(); // Гарантированное освобождение в finally
}

Когда использовать synchronized:

  • В простых случаях, когда достаточно базовой синхронизации.
  • Когда нужна встроенная поддержка мониторов (методы wait(), notify()).

Когда использовать Lock:

  • Когда нужны расширенные возможности (таймауты, прерывания, честность).
  • Для реализации read-write блокировок.
  • Когда логика получения/освобождения блокировки не укладывается в блоковый scope synchronized.

Ответ 18+ 🔞

А, слушай, про эти ваши лок-локи! Ну, блядь, классика же! Все эти synchronized — они как старые добрые валенки: надёжно, просто, но в грязь зашёл — и нихуя не скинешь, пока до дома не доплетёшься.

А вот этот ваш java.util.concurrent.locks.Lock — это уже, сука, продвинутые берцы на липучках. Выглядит сложнее, но нихуя как гибко!

Смотри, в чём прикол-то, ёпта:

Чем эти лок-замки, блядь, круче?

  1. Можно постучаться и уйти. Ну реально, представь: подошёл к двери (критической секции), дернул ручку — заперто. С synchronized ты стоишь, блядь, как лох, и ждёшь, пока тебя впустят, хоть до пенсии. А с Lock? А с локом ты такой: «Э, я подожду две секунды, и если не откроют — я, блядь, пошёл пить чай в другое место!» И не висит поток, как сопля.

    if (lock.tryLock(2, TimeUnit.SECONDS)) { // Жду, бля, две секунды и всё!
        try {
            // Делаю свои делишки
        } finally {
            lock.unlock(); // Не забыть, а то всех заблокируешь!
        }
    } else {
        // Да похуй, не получилось — пойду в кафешку
    }
  2. Можно прервать ожидание. Ты стоишь, ждёшь, а тебе в ухо: «Вань, всё, давай завязывай, домой иди!». И ты, блядь, можешь взять и уйти (lockInterruptibly()), а не торчать там, как приклеенный.

  3. Честность, блядь! ReentrantLock можно создать честным — как очередь в поликлинике. Кто первый пришёл, тот первый и зайдёт. А не как обычно: самый наглый лезет без очереди. Голодания потоков меньше — спокойствие, блядь, в коллективе.

  4. Читатели отдельно, писатели отдельно. Вот это, сука, мощь! ReentrantReadWriteLock. Пять потоков могут одновременно читать одну бумажку — им похуй друг на друга. Но как только один возжелал писать — все, пиздец, все читатели ждут, писатель один царь и бог. Производительность, блядь, взлетает, если читателей дохуя, а писатель редко.

Но, сука, с великой силой приходит великая ответственность! Шаблон использования — догма, блядь:

Lock lock = new ReentrantLock();
// ...
lock.lock(); // ВСЕГДА, блядь, перед try! Иначе в finally можешь разблокировать то, чего не блокировал!
try {
    // Твоя священная критическая секция
} finally {
    lock.unlock(); // Это святое! Гарантированно отпускаем, даже если всё пошло по пизде!
}

Забыл unlock() в finally? Всё, пидор, deadlock накрыл тебя медным тазом. Все потоки упёрлись и ждут вечность.

Так когда что брать-то?

  • synchronized — когда ты ленивая жопа и делаешь что-то простое. Или когда тебе нахуй не сдались эти wait()/notify() — они там внутри уже прикручены.
  • Lock — когда задача не влезает в простые рамки. Нужны таймауты, прерывания, честная очередь или разделение на читателей/писателей. Когда логика захвата-освобождения — это такой квест, что в блок synchronized её не запихнуть, хоть ты тресни.

Короче, synchronized — это как отвёртка. Lock — это, блядь, целый швейцарский нож с кучей лезвий. Но если тебе просто винт закрутить — зачем весь этот овердохуища инструмент таскать? Выбирай по ситуации, а не потому что модно.