Смешение синхронизированного() с ReentrantLock.lock()

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

Мое предположение: "Нет", но я надеюсь ошибиться.

Пример:

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

ReentrantLock lock = new ReentrantLock();

Тема 1:

synchronized (lock) {
    // blah
}

Режимы Thread 2:

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

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

Ответы

Ответ 1

Нет, Thread 2 может lock(), даже если Thread 1 является synchronized на том же lock. Это то, что документация должна сказать:

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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