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
实施必须执行与内置监视器锁相同的内存同步语义,如The Java Language Specification (17.4 Memory Model) 所述 :
lock
操作具有与成功锁定动作相同的内存同步效果。 unlock
操作具有与成功解锁动作相同的内存同步效果。 锁定采集(可中断,不可中断和定时)的三种形式在性能特征,排序保证或其他实施质量方面可能不同。 此外,在给定的Lock
课程中,中断正在获取锁的能力可能不可用。 因此,不需要实现对所有三种形式的锁获取完全相同的保证或语义,也不需要支持正在进行的锁获取的中断。 需要一个实现来清楚地记录每个锁定方法提供的语义和保证。 它还必须遵守此接口中定义的中断语义,只要支持锁获取的中断,即全部或仅在方法输入。
由于中断通常意味着取消,并且检查中断通常是不频繁的,所以实现可以有利于通过正常方法返回来响应中断。 即使可以显示中断发生在另一个动作可能已经解除了线程之后,这是真的。 一个实现应该记录这个行为。
ReentrantLock
, Condition
, ReadWriteLock
Modifier and Type | Method and Description |
---|---|
void |
lock()
获得锁。
|
void |
lockInterruptibly()
获取锁定,除非当前线程是
interrupted 。
|
Condition |
newCondition()
返回一个新 Condition 绑定到该实例Lock 实例。
|
boolean |
tryLock()
只有在调用时才可以获得锁。
|
boolean |
tryLock(long time, TimeUnit unit)
如果在给定的等待时间内是空闲的,并且当前的线程尚未得到
interrupted,则获取该锁。
|
void |
unlock()
释放锁。
|
void lock()
如果锁不可用,则当前线程将被禁用以进行线程调度,并处于休眠状态,直到获取锁。
实施注意事项
Lock
实现可能能够检测锁的错误使用,例如将导致死锁的调用,并且可能在这种情况下抛出(未检查)异常。 情况和异常类型必须由Lock
实现记录。
void lockInterruptibly() throws InterruptedException
获取锁,如果可用并立即返回。
如果锁不可用,那么当前线程将被禁用以进行线程调度,并且处于休眠状态,直到发生两件事情之一:
如果当前线程:
InterruptedException
被关上,当前线程的中断状态被清除。
实施注意事项
在某些实现中中断锁获取的能力可能是不可能的,如果可能的话可能是昂贵的操作。 程序员应该知道,可能是这种情况。 在这种情况下,实施应该记录。
一个实现可以有利于通过正常的方法返回来响应中断。
Lock
实现可能能够检测到锁的错误使用,例如将导致死锁的调用,并且可能在这种情况下抛出(未检查)异常。 情况和异常类型必须由Lock
实现记录。
InterruptedException
- 如果当前线程在获取锁定期间中断(并且支持锁定获取的中断)
boolean tryLock()
如果可用,则获取锁定,并立即返回值为true
。 如果锁不可用,则此方法将立即返回值为false
。
此方法的典型用法是:
Lock lock = ...; if (lock.tryLock()) { try { // manipulate protected state } finally { lock.unlock(); } } else { // perform alternative actions }
此用法可确保锁定已被取消,如果未获取锁定,则不会尝试解锁。
true
如果锁被收购,
false
false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException
如果锁可用,此方法将立即返回值为true
。 如果锁不可用,则当前线程将被禁用以进行线程调度,并且处于休眠状态,直至发生三件事情之一:
如果锁获取,则返回值true
。
如果当前线程:
InterruptedException
被关上,当前线程的中断状态被清除。
如果指定的等待时间过去,则返回值false
。 如果时间小于或等于零,该方法根本不会等待。
实施注意事项
在某些实现中中断锁获取的能力可能是不可能的,如果可能的话可能是昂贵的操作。 程序员应该知道,可能是这种情况。 在这种情况下,实施应该记录。
实现可以有助于通过正常的方法返回来响应中断或报告超时。
Lock
实现可能能够检测到锁的错误使用,例如将导致死锁的调用,并且可能在这种情况下抛出(未检查)异常。 情况和异常类型必须由Lock
实现记录。
time
- 等待锁的最长时间
unit
-
time
参数的时间单位
true
如果锁已被获取,并且
false
如果在获取锁之前经过的等待时间
InterruptedException
- 如果当前线程在获取锁定时中断(并且支持锁定获取的中断)
void unlock()
实施注意事项
一个Lock
实现通常会限制哪个线程可以释放锁(通常只有锁的持有者可以释放它),并且如果限制被违反则可能会引发(未检查)异常。 任何限制和异常类型必须由Lock
实现记录。
Condition newCondition()
Condition
绑定到该实例Lock
实例。
在等待条件之前,锁必须由当前线程保持。 呼叫Condition.await()
将在等待之前将原子释放锁,并在等待返回之前重新获取锁。
实施注意事项
Condition
实例的确切操作取决于Lock
实现,必须由该实现记录。
Condition
实例,该Lock
实例
UnsupportedOperationException
- 如果这个
Lock
实现不支持条件