Spec-Zone.ru › OpenJDK 21

Интерфейс 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
См. также:
  • ReentrantLock
  • Condition
  • ReadWriteLock

Краткое описание методов

Модификатор и тип Метод Описание
void lock()
Получает блокировку.
void lockInterruptibly()
Получает блокировку, если текущий поток не прерван.
Condition newCondition()
Возвращает новый Condition экземпляр, привязанный к этому экземпляру Lock.
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, 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API