java.util.concurrent
API предоставляет класс с именем as Lock
, который в основном сериализует элемент управления для доступа к критическому ресурсу. Это дает такой метод, как park()
и unpark()
.
Мы можем делать подобные вещи, если мы можем использовать synchronized
ключевое слово wait()
и notify() notifyAll()
методы и.
Мне интересно, какой из них лучше на практике и почему?
Ответы:
Если вы просто блокируете объект, я бы предпочел использовать
synchronized
Пример:
Вы должны делать это
try{} finally{}
везде.Принимая во внимание, что с синхронизированным, это супер ясно и невозможно ошибиться:
Тем не менее,
Lock
s может быть более полезным для более сложных вещей, которые вы не можете получить и выпустить таким чистым способом. Честно говоря, я бы предпочел не использовать голыеLock
s в первую очередь и просто использовать более сложный контроль параллелизма, такой как aCyclicBarrier
или aLinkedBlockingQueue
, если они удовлетворяют вашим потребностям.Я никогда не имел оснований для использования
wait()
или ,notify()
но могут быть некоторые хорошие.источник
std::lock_guard
Я обнаружил, что
Lock
иCondition
(и другие новыеconcurrent
классы) просто больше инструментов для панели инструментов. Я мог делать почти все, что мне было нужно, со своим старым молотком (synchronized
ключевое слово), но в некоторых ситуациях его было неловко использовать. Некоторые из этих неловких ситуаций стали намного проще, когда я добавил в свой набор инструментов больше инструментов: резиновый молоток, молоток с шариковой ручкой, монтировку и несколько ударов по гвоздям. тем не мение , мой старый молоток с раздвоенным хвостом все еще видит свою долю использования.Я не думаю, что один действительно «лучше», чем другой, но, скорее, каждый лучше подходит для разных задач. Короче говоря, простая модель и ориентированная на область действия природа
synchronized
помогают защитить меня от ошибок в моем коде, но эти же преимущества иногда являются помехами в более сложных сценариях. Это более сложные сценарии, для которых был создан параллельный пакет. Но использование конструкций более высокого уровня требует более четкого и тщательного управления в коде.===
Я думаю , что JavaDoc делает хорошую работу описания различия между
Lock
иsynchronized
(выделено мной):источник
Вы можете достичь все коммунальных услуги в java.util.concurrent делать с низкоуровневыми примитивами , такими как
synchronized
,volatile
или ожидание / извещатьТем не менее, параллелизм сложен, и большинство людей по крайней мере некоторые его части понимают неправильно, что делает их код неправильным или неэффективным (или и тем, и другим).
Параллельный API предоставляет высокоуровневый подход, который проще (и, как таковой, безопаснее) использовать. В двух словах, вам не нужно больше использовать
synchronized, volatile, wait, notify
напрямую.Сам класс Lock находится на нижнем уровне этой панели инструментов, вам может даже не потребоваться использовать его напрямую (вы можете использовать
Queues
и Semaphore, и прочее, и т. Д. Большую часть времени).источник
java.util.concurrent
которое легче [в целом], чем языковые особенности (synchronized
и т. Д.). Когда вы используете,java.util.concurrent
вы должны привыкнуть к завершениюlock.lock(); try { ... } finally { lock.unlock() }
перед написанием кода, тогда как с a уsynchronized
вас все в порядке с самого начала. На этом основании я бы сказал,synchronized
что проще (если вы хотите, чтобы его поведение), чемjava.util.concurrent.locks.Lock
. пар 4Есть 4 основных фактора, почему вы хотите использовать
synchronized
илиjava.util.concurrent.Lock
.Примечание: синхронная блокировка - это то, что я имею в виду, когда говорю внутреннюю блокировку.
Когда в Java 5 появились ReentrantLocks, оказалось, что они имеют довольно заметную разницу в пропускной способности, чем встроенная блокировка. Если вы ищете более быстрый механизм блокировки и используете 1.5, рассмотрите jucReentrantLock. Собственная блокировка Java 6 теперь сопоставима.
У jucLock есть разные механизмы блокировки. Блокировка прерывается - попытка блокировки до тех пор, пока блокирующая нить не будет прервана временная блокировка - попытка заблокировать на определенное время и сдаться, если у вас ничего не получится; tryLock - попытка блокировки, если какой-то другой поток удерживает блокировку, сдаться. Это все включено помимо простого замка. Внутренняя блокировка предлагает только простую блокировку
источник
Я хотел бы добавить еще кое-что поверх ответа Берта Ф.
Locks
поддержка различных методов для более точного управления блокировками, которые более выразительны, чем неявные мониторы (synchronized
блокировки)Преимущества блокировки по синхронизации со страницы документации
Использование синхронизированных методов или операторов обеспечивает доступ к неявной блокировке монитора, связанной с каждым объектом, но заставляет все получение и освобождение блокировки происходить блочно-структурированным способом.
Реализации блокировки предоставляют дополнительные функциональные возможности по сравнению с использованием синхронизированных методов и операторов, предоставляя неблокирующую попытку получения
lock (tryLock())
, попытку получить блокировку, которая может быть прервана (lockInterruptibly()
и попытку получить блокировку, которая можетtimeout (tryLock(long, TimeUnit))
.Класс Lock также может предоставлять поведение и семантику, которые сильно отличаются от таковых для неявной блокировки монитора, например, гарантированное упорядочение, использование без повторного входа или обнаружение взаимоблокировки
ReentrantLock : Проще говоря, насколько я понимаю,
ReentrantLock
позволяет объекту повторно входить из одного критического раздела в другой критический раздел. Поскольку у вас уже есть блокировка для входа в одну критическую секцию, вы можете использовать другую критическую секцию для того же объекта, используя текущую блокировку.ReentrantLock
ключевые особенности согласно этой статьеВы можете использовать
ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
для дальнейшего контроля гранулярной блокировки операций чтения и записи.Помимо этих трех ReentrantLocks, Java 8 предоставляет еще один замок
StampedLock:
Вы можете использовать эти штампы, чтобы снять блокировку или проверить, действительна ли блокировка. Кроме того, штампованные блокировки поддерживают другой режим блокировки, называемый оптимистической блокировкой.
Взгляните на эту статью об использовании различных типов
ReentrantLock
иStampedLock
замков.источник
Основным отличием является справедливость, иными словами, запросы обрабатываются FIFO или может быть завал? Синхронизация на уровне метода обеспечивает справедливое или FIFO распределение блокировки. С помощью
или
не гарантирует справедливости.
Если у вас есть много споров о блокировке, вы можете легко столкнуться с блокировкой, когда новые запросы блокируют, а более старые запросы застревают. Я видел случаи, когда 200 потоков поступали в короткие сроки для блокировки, а 2-й поток, который поступил, обрабатывался последним. Это нормально для некоторых приложений, но для других это смертельно.
См. Книгу Брайана Гетца «Параллелизм Java на практике», раздел 13.3, для полного обсуждения этой темы.
источник
Книга Брайана Гетца «Java Concurrency In Practice», раздел 13.3: «... Как и стандартный ReentrantLock, встроенная блокировка не дает никаких детерминированных гарантий справедливости, но гарантии статистической справедливости большинства реализаций блокировки достаточно хороши практически для всех ситуаций ...»
источник
Блокировка делает жизнь программистов проще. Вот несколько ситуаций, которые могут быть легко достигнуты с помощью блокировки.
Пока блокировка и условия строятся на синхронизированном механизме. Таким образом, безусловно, может быть в состоянии достичь той же функциональности, что вы можете достичь с помощью блокировки. Однако решение сложных сценариев с синхронизацией может осложнить вашу жизнь и отклонить вас от решения актуальной проблемы.
источник
Основное различие между блокировкой и синхронизацией:
источник
Блокировка и синхронизация блока служат одной и той же цели, но это зависит от использования. Рассмотрим следующую часть
В приведенном выше случае, если поток входит в блок синхронизации, другой блок также блокируется. Если на одном объекте несколько таких блоков синхронизации, все блоки заблокированы. В таких ситуациях java.util.concurrent.Lock можно использовать для предотвращения нежелательной блокировки блоков.
источник