Spec-Zone.ru › OpenJDK 8

Интерфейс 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()

Возвращает новый экземпляр 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, 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.

Spec-Zone.ru

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