Интерфейс Lock
- Все известные реализующие классы:
-
ReentrantLock,ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock
public interface Lock
Lock реализации предоставляют более расширенные операции блокировки, чем можно получить с использованием synchronized методов и операторов. Они позволяют более гибкую структуру, могут иметь совершенно разные свойства и могут поддерживать несколько связанных Condition объектов. Блокировка — это инструмент для управления доступом к общему ресурсу несколькими потоками. Обычно блокировка обеспечивает эксклюзивный доступ к общему ресурсу: только один поток за раз может получить блокировку, и любой доступ к общему ресурсу требует, чтобы блокировка была получена в первую очередь. Однако некоторые блокировки могут допускать одновременный доступ к общему ресурсу, например, чтение блокировки ReadWriteLock.
Использование synchronized методов или операторов предоставляет доступ к неявной блокировке монитора, связанной с каждым объектом, но принуждает все получение и освобождение блокировки происходить в блочно-структурированном виде: при получении нескольких блокировок они должны быть освобождены в обратном порядке, и все блокировки должны быть освобождены в той же лексической области, в которой они были получены.
Хотя механизм области действия для synchronized методов и операторов делает программирование с блокировками монитора намного проще и помогает избежать многих распространенных ошибок программирования, связанных с блокировками, есть случаи, когда вам нужно работать с блокировками более гибким способом. Например, некоторые алгоритмы для обхода конкурирующих структур данных требуют использования "ручной передачи" или "цепочечной блокировки": вы получаете блокировку узла А, затем узла В, затем освобождаете А и получаете С, затем освобождаете В и получаете 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 реализации должны применять ту же семантику синхронизации памяти, что и встроенная блокировка монитора, как описано в главе 17 спецификации языка Java:
- Успешная
lockоперация имеет те же эффекты синхронизации памяти, что и успешное действие Lock. - Успешная
unlockоперация имеет те же эффекты синхронизации памяти, что и успешное действие Unlock.
Соображения по реализации
Три формы получения блокировки (прерывистая, непрерывистая и временная) могут отличаться по характеристикам производительности, гарантиям порядка или другим качествам реализации. Более того, возможность прервать продолжающееся получение блокировки может быть недоступна в данном классе Lock. Следовательно, реализация не обязана определять точно такие же гарантии или семантику для всех трех форм получения блокировки, ни обязана поддерживать прерывание процесса получения блокировки. Реализация должна четко документировать семантику и гарантии, предоставляемые каждым из методов блокировки. Она также должна соблюдать семантику прерывания, как определено в этом интерфейсе, в той мере, в которой поддержка прерывания процесса получения блокировки поддерживается: это может быть полностью или только при входе в метод.
Поскольку прерывание, как правило, подразумевает отмену, и проверки на прерывание часто нечастые, реализация может отдавать приоритет реагированию на прерывание над нормальным возвратом метода. Это верно даже если можно показать, что прерывание произошло после того, как другой процесс мог разблокировать поток. Реализация должна документировать это поведение.
- См. Спецификацию языка Java:
- 17.4 Модель памяти
- С тех пор:
- 1.5
- См. также:
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
void |
lock() |
Получает блокировку. |
void |
lockInterruptibly() |
Получает блокировку, если текущий поток не прерван. |
Condition |
newCondition() |
Возвращает новый Condition экземпляр, привязанный к этому экземпляру Lock. |
boolean |
tryLock() |
Получает блокировку только если она свободна в момент вызова. |
boolean |
tryLock |
Получает блокировку, если она свободна в течение заданного времени ожидания, и текущий поток не был прерван. |
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, 2023, 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.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/locks/Lock.html