Смешивание synchronized() с ReentrantLock.lock()

Используют ли в Java ReentrantLock.lock() и ReetrantLock.unlock() тот же механизм блокировки, что и synchronized()?

Моя догадка "Нет", но я надеюсь, что ошибаюсь.

Пример:

Представьте, что поток 1 и поток 2 имеют доступ к:

ReentrantLock lock = new ReentrantLock();

Поток 1 работает:

synchronized (lock) {
    // blah
}

Поток 2 работает:

lock.lock();
try {
    // blah
}
finally {
    lock.unlock();
}

Предположим, что сначала поток 1 достигает своей части, а затем поток 2 до того, как поток 1 завершится: будет ли поток 2 ждать, пока поток 1 покинет блок synchronized(), или он продолжит работу?


person James Jensen    schedule 24.05.2010    source источник


Ответы (3)


Нет, поток 2 может lock(), даже если поток 1 является synchronized на том же lock. Об этом говорится в документации. должен сказать:

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

person erickson    schedule 24.05.2010
comment
Вот что я понял. Есть одно место, где мне нужно использовать ReetrantLock.tryLock(), и я надеялся обойтись без synchronized везде. Спасибо. - person James Jensen; 25.05.2010

Эти два механизма различны. Реализация/производительность:

  • синхронизированный механизм использует механизм блокировки, который «встроен» в JVM; базовый механизм зависит от конкретной реализации JVM, но обычно использует комбинацию необработанных compare-and- инструкция установки операции (CAS) для случаев, когда блокировка не оспаривается, а также базовые механизмы блокировки, предоставляемые ОС;
  • классы блокировки, такие как ReentrantLock, в основном закодированы на чистой Java (с помощью библиотеки, представленной в Java 5, которая предоставляет инструкции CAS и депланирование потоков для Java), и поэтому они несколько более стандартизированы для ОС и более управляемы (см. ниже).

В некоторых случаях явные блокировки могут работать лучше. Если вы посмотрите на это сравнение механизмов блокировки, которое я выполнил в Java 5, вы увидите что в этом конкретном тесте (несколько потоков, обращающихся к массиву) явные классы блокировки, настроенные в «несправедливом» режиме (желтый и голубой треугольники), обеспечивают большую пропускную способность, чем обычная синхронизация (фиолетовые стрелки).

(Я также должен сказать, что производительность synchronized была улучшена в более поздних версиях Hotspot; в последних версиях или даже при других обстоятельствах этого может быть не так много — очевидно, это один тест в одной среде.)

Функционально:

  • синхронизированный механизм обеспечивает минимальную функциональность (вы можете блокировать и разблокировать, блокировка — это операция по принципу «все или ничего», вы больше зависите от алгоритма, который выбрали разработчики ОС), хотя и с преимуществом встроенного синтаксиса и некоторого мониторинга. встроен в JVM;
  • явные классы блокировки обеспечивают больший контроль, в частности, вы можете указать «справедливую» блокировку, блокировку с тайм-аутом, переопределить, если вам нужно изменить поведение блокировки...
person Neil Coffey    schedule 25.05.2010

Почему вы сделали баланс статическим в классе Account? Удалите статику, и она должна работать.

Кроме того, у вас есть вопрос об использовании ваших потоков. В вашем TestMain вы создаете новые потоки и назначаете запускаемые объекты, такие как WithdrawRequests и DepositRequests. Но опять же вы создаете новые потоки внутри конструкторов этих исполняемых модулей. Это приведет к тому, что метод run будет выполнен дважды!

person lasantha    schedule 03.05.2011