Spec-Zone.ru › OpenJDK 24

Интерфейс 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(); // lock() as the last statement before the try block
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock(); // unlock() as the first statement in the finally block
 }
При блокировании и разблокировании в разных областях необходимо следить за тем, чтобы весь код, выполняемый, пока блокировка удерживается, был защищен 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.

Throws:
InterruptedException - если текущий поток прерывается во время захвата блокировки (и прерывание захвата блокировки поддерживается)

tryLock

boolean tryLock()
Захватывает блокировку только в том случае, если она свободна в момент вызова.

Захватывает блокировку, если она доступна, и немедленно возвращает значение true. Если блокировка недоступна, этот метод немедленно возвращает значение false.

Типичный шаблон использования этого метода:

 
 Lock lock = ...;
 if (lock.tryLock()) {
   try {
     // manipulate protected state
   } finally {
     lock.unlock();
   }
 } else {
   // perform alternative actions
 }
Это использование гарантирует, что блокировка разблокирована, если она была захвачена, и не пытается разблокировать её, если блокировка не была захвачена.
Returns:
true, если блокировка была захвачена, и false в противном случае

tryLock

boolean tryLock(long time, TimeUnit unit) throws InterruptedException
Захватывает блокировку, если она свободна в течение заданного времени ожидания и текущий поток не прерван.

Если блокировка доступна, этот метод возвращает значение true немедленно. Если блокировка недоступна, текущий поток становится неактивным для целей планирования потоков и находится в ожидании, пока не произойдёт одно из трёх событий:

  • Текущий поток захватывает блокировку; или
  • Другой поток прерывает текущий поток, и прерывание процесса захвата блокировки поддерживается; или
  • Заданное время ожидания истекает

Если блокировка захвачена, возвращается значение true.

Если у текущего потока:

  • Флаг прерывания установлен при входе в этот метод; или
  • Поток прерывается во время захвата блокировки, и прерывание процесса захвата блокировки поддерживается,
то выбрасывается InterruptedException, и флаг прерывания текущего потока сбрасывается.

Если заданное время ожидания истекает, возвращается значение false. Если время равно или меньше нуля, метод не будет ожидать.

Соображения по реализации

Возможность прервать захват блокировки в некоторых реализациях может отсутствовать или быть дорогостоящей операцией. Разработчик должен быть об этом осведомлён. Реализация должна документировать подобные случаи.

Реализация может отдавать приоритет обработке прерывания перед обычным возвратом метода или сообщением о тайм-ауте.

Реализация Lock может обнаруживать ошибочное использование блокировки, например, вызов, который приведет к тупику, и в таких случаях может выбросить (непроверенное) исключение. Обстоятельства и тип исключения должны быть задокументированы реализацией Lock.

Parameters:
time - максимальное время ожидания блокировки
unit - единица измерения времени для аргумента time
Returns:
true, если блокировка была захвачена, и false, если время ожидания истекло до захвата блокировки
Throws:
InterruptedException - если текущий поток прерывается во время захвата блокировки (и прерывание захвата блокировки поддерживается)

unlock

void unlock()
Освобождает блокировку.

Соображения по реализации

Реализация Lock обычно накладывает ограничения на тот поток, который может освободить блокировку (обычно только владелец блокировки может её освободить) и может выбросить (непроверенное) исключение, если ограничение нарушено. Любые ограничения и тип исключения должны быть задокументированы реализацией Lock.

newCondition

Condition newCondition()
Возвращает новую инстанцию Condition, связанную с этим экземпляром Lock.

Перед ожиданием условия текущий поток должен удерживать блокировку. Вызов Condition.await() атомарно освобождает блокировку перед ожиданием и повторно захватывает блокировку перед возвратом из ожидания.

Соображения по реализации

Точное поведение экземпляра Condition зависит от реализации Lock и должно быть задокументировано этой реализацией.

Returns:
Новый экземпляр Condition для этого экземпляра Lock
Throws:
UnsupportedOperationException - если реализация Lock не поддерживает условия

© 1993, 2025, 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://download.java.net/java/early_access/jdk24/docs/api/java.base/java/util/concurrent/locks/Lock.html

Spec-Zone.ru

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