Spec-Zone.ru › OpenJDK 17

Интерфейс 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 реализации обязательно должны применять те же семантики синхронизации памяти, что и встроенная мониторная блокировка, как описано в главе 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, 2021, 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/17/docs/api/java.base/java/util/concurrent/locks/Lock.html

Spec-Zone.ru

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