Интерфейс Lock
- Все известные реализующие классы:
- ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
public interface Lock
Lock реализации предоставляют более расширенные операции блокировки, чем можно получить, используя synchronized методы и операторы. Они позволяют более гибкую структуризацию, могут иметь совершенно другие свойства и могут поддерживать несколько связанных объектов Condition.
Блокировка — это инструмент для управления доступом к общему ресурсу несколькими потоками. Обычно блокировка обеспечивает исключительный доступ к общему ресурсу: только один поток за раз может получить блокировку, и любой доступ к общему ресурсу требует, чтобы блокировка была получена в первую очередь. Однако некоторые блокировки могут позволять одновременный доступ к общему ресурсу, например, чтение блокировки ReadWriteLock.
Использование synchronized методов или операторов предоставляет доступ к неявной мониторной блокировке, связанной с каждым объектом, но принуждает все получение и освобождение блокировки происходить в блочной структуре: когда несколько блокировок получены, они должны быть освобождены в обратном порядке, и все блокировки должны быть освобождены в той же лексической области, в которой они были получены.
Хотя механизм области действия для synchronized методов и операторов делает программирование с мониторными блокировками гораздо проще и помогает избежать многих распространенных ошибок программирования, связанных с блокировками, есть случаи, когда вам нужно работать с блокировками более гибко. Например, некоторые алгоритмы для обхода одновременно доступных структур данных требуют использования «ручной передачи» или «цепочной блокировки»: вы получаете блокировку узла A, затем узла B, затем освобождаете A и получаете C, затем освобождаете B и получаете D и так далее. Реализации интерфейса Lock позволяют использовать такие методы, позволяя получать и освобождать блокировку в разных областях и позволяя получать и освобождать несколько блокировок в любом порядке.
Эта повышенная гибкость влечет за собой дополнительную ответственность. Отсутствие структурированной блокировки отменяет автоматическое освобождение блокировок, которое происходит с synchronized методами и операторами. В большинстве случаев следует использовать следующий фрагмент кода:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
} При получении и освобождении блокировки в разных областях необходимо позаботиться о том, чтобы весь код, выполняемый при удерживании блокировки, был защищен конструкциями try-finally или try-catch, чтобы гарантировать, что блокировка будет освобождена при необходимости. Lock реализации обеспечивают дополнительную функциональность по сравнению с использованием synchronized методов и операторов, предоставляя непротиворечивую попытку получить блокировку (tryLock()), попытку получения блокировки, которая может быть прервана (lockInterruptibly(), и попытку получения блокировки, которая может быть приостановлена (tryLock(long, TimeUnit)).
Класс Lock также может предоставить поведение и семантику, которые существенно отличаются от неявной мониторной блокировки, например, гарантированный порядок, нерекурсивное использование или обнаружение тупиков. Если реализация предоставляет такую специализированную семантику, то реализация должна документировать эту семантику.
Обратите внимание, что экземпляры Lock — это обычные объекты и могут сами использоваться в качестве целевого объекта в операторе synchronized. Получение мониторной блокировки экземпляра Lock не имеет определенной связи с вызовом любого из методов lock() этого экземпляра. Рекомендуется, чтобы избежать путаницы, никогда не использовать экземпляры Lock таким образом, за исключением их собственной реализации.
Если не указано иное, передача значения null для любого параметра приведет к тому, что будет выброшено исключение NullPointerException.
Синхронизация памяти
Все Lock реализации должны соблюдать те же семантики синхронизации памяти, что и встроенная мониторная блокировка, как описано в Спецификации языка Java (17.4 Модель памяти):
- Успешная операция
lockимеет те же эффекты синхронизации памяти, что и успешное действие Lock. - Успешная операция
unlockимеет те же эффекты синхронизации памяти, что и успешное действие Unlock.
Учёт реализации
Три формы получения блокировки (прерывистая, непрерывистая и с таймаутом) могут отличаться по производительности, гарантиям порядка или другим качествам реализации. Кроме того, возможность прерывания текущего получения блокировки может быть недоступна в данном классе Lock. Следовательно, реализация не обязана определять точно те же гарантии или семантику для всех трёх форм получения блокировки, ни она не обязана поддерживать прерывание текущего получения блокировки. Реализация должна четко документировать семантику и гарантии, предоставляемые каждым из методов блокировки. Она также должна соблюдать семантику прерывания, как определено в этом интерфейсе, в той степени, в которой прерывание получения блокировки поддерживается: полностью или только при входе в метод.
Поскольку прерывание обычно подразумевает отмену, а проверки на прерывание часто происходят нечасто, реализация может отдавать предпочтение реагированию на прерывание по сравнению с нормальным возвратом из метода. Это верно, даже если можно показать, что прерывание произошло после того, как другой процесс мог разблокировать поток. Реализация должна документировать это поведение.
- С момента:
- 1.5
- См. также:
-
ReentrantLock,Condition,ReadWriteLock
Методы
| Модификатор и тип | Метод и описание |
|---|---|
void |
lock() Получает блокировку. |
void |
lockInterruptibly() Получает блокировку, если текущий поток не прерван. |
Condition |
newCondition() Возвращает новый экземпляр |
boolean |
tryLock() Получает блокировку только если она свободна в момент вызова. |
boolean |
tryLock(long time,
TimeUnit unit) Получает блокировку, если она свободна в течение заданного времени ожидания, и текущий поток не прерван. |
void |
unlock() Освобождает блокировку. |
Методы
lock
void lock()
Приобретает блокировку.
Если блокировка недоступна, текущий поток отключается от планирования потоков и остается неактивным до тех пор, пока блокировка не будет приобретена.
Рекомендации по реализации
Реализация Lock может обнаружить ошибочное использование блокировки, например, вызов, который приведет к тупику, и может выбросить (непроверяемое) исключение в таких случаях. Обстоятельства и тип исключения должны быть задокументированы этой реализацией Lock.
lockInterruptibly
void lockInterruptibly()
throws InterruptedException Приобретает блокировку, если текущий поток не прерван.
Приобретает блокировку, если она доступна, и возвращает значение немедленно.
Если блокировка недоступна, текущий поток отключается от планирования потоков и остается неактивным до тех пор, пока не произойдёт одно из двух событий:
- Блокировка приобретена текущим потоком; или
- Другой поток прерывает текущий поток, и прерывание приобретения блокировки поддерживается.
Если текущий поток:
- имеет установленный флаг прерывания при входе в этот метод; или
- прерывается при приобретении блокировки, и прерывание приобретения блокировки поддерживается,
InterruptedException, и флаг прерывания текущего потока сбрасывается. Рекомендации по реализации
Возможность прерывания приобретения блокировки в некоторых реализациях может быть недоступна, а если доступна, то может быть дорогостоящей операцией. Программист должен знать об этом. Реализация должна документировать такие случаи.
Реализация может отдавать приоритет реагированию на прерывание перед обычным возвратом метода.
Реализация Lock может обнаружить ошибочное использование блокировки, например, вызов, который приведет к тупику, и может выбросить (непроверяемое) исключение в таких случаях. Обстоятельства и тип исключения должны быть задокументированы этой реализацией Lock.
- Исключения:
-
InterruptedException- если текущий поток прерывается во время приобретения блокировки (и прерывание приобретения блокировки поддерживается)
tryLock
boolean tryLock()
Приобретает блокировку только если она свободна в момент вызова.
Приобретает блокировку, если она доступна, и возвращает значение немедленно со значением true. Если блокировка недоступна, этот метод возвращает значение немедленно со значением false.
Типичный шаблон использования для этого метода:
Lock lock = ...;
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
} Этот шаблон гарантирует, что блокировка разблокируется, если она была приобретена, и не пытается разблокировать её, если блокировка не была приобретена.- Возвращает:
-
trueесли блокировка была приобретена иfalseв противном случае
tryLock
boolean tryLock(long time,
TimeUnit unit)
throws InterruptedException Приобретает блокировку, если она свободна в течение заданного времени ожидания, и текущий поток не прерван.
Если блокировка доступна, этот метод возвращает значение немедленно со значением true. Если блокировка недоступна, текущий поток отключается от планирования потоков и остается неактивным до тех пор, пока не произойдёт одно из трёх событий:
- Блокировка приобретена текущим потоком; или
- Другой поток прерывает текущий поток, и прерывание приобретения блокировки поддерживается; или
- Заданное время ожидания истекло
Если блокировка приобретена, возвращается значение true.
Если текущий поток:
- имеет установленный флаг прерывания при входе в этот метод; или
- прерывается при приобретении блокировки, и прерывание приобретения блокировки поддерживается,
InterruptedException, и флаг прерывания текущего потока сбрасывается. Если заданное время ожидания истекло, возвращается значение false. Если время равно или меньше нуля, метод не будет ожидать вообще.
Рекомендации по реализации
Возможность прерывания приобретения блокировки в некоторых реализациях может быть недоступна, а если доступна, то может быть дорогостоящей операцией. Программист должен знать об этом. Реализация должна документировать такие случаи.
Реализация может отдавать приоритет реагированию на прерывание перед обычным возвратом метода или сообщением о тайм-ауте.
Реализация Lock может обнаружить ошибочное использование блокировки, например, вызов, который приведет к тупику, и может выбросить (непроверяемое) исключение в таких случаях. Обстоятельства и тип исключения должны быть задокументированы этой реализацией Lock.
- Параметры:
-
time- максимальное время ожидания блокировки -
unit- единица измерения времени для аргументаtime - Возвращает:
-
trueесли блокировка была приобретена иfalseесли время ожидания истекло до приобретения блокировки - Исключения:
-
InterruptedException- если текущий поток прерывается во время приобретения блокировки (и прерывание приобретения блокировки поддерживается)
unlock
void unlock()
Освобождает блокировку.
Рекомендации по реализации
Реализация Lock обычно налагает ограничения на то, какой поток может освободить блокировку (обычно только владелец блокировки может её освободить) и может выбросить (непроверяемое) исключение, если ограничение нарушено. Любые ограничения и тип исключения должны быть задокументированы этой реализацией Lock.
newCondition
Condition newCondition()
Возвращает новый экземпляр Condition, связанный с этим экземпляром Lock.
Перед ожиданием на условии текущий поток должен удерживать блокировку. Вызов Condition.await() атомарно освобождает блокировку перед ожиданием и повторно приобретает блокировку перед возвратом из ожидания.
Рекомендации по реализации
Точное поведение экземпляра Condition зависит от реализации Lock и должно быть задокументировано этой реализацией.
- Возвращает:
- Новый экземпляр
Conditionдля этого экземпляраLock - Исключения:
-
UnsupportedOperationException- если эта реализацияLockне поддерживает условия
© 1993, 2020, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.