Lock接口
接口简介
相比同步方法块和同步方法,Lock的实例提供了更多的可扩展的所操作。它允许更灵活的结构,可能有不同的属性,并且可以支持多个关联的Condition。
锁是在多线程环境下控制访问公共资源的工具。通常,一个锁提供了对公共资源独有的访问权限:在一个时间,只有一个线程可以获取锁,并且所有对于公共资源的访问首先要获取到锁。当然也有一些锁可以同时的访问资源,比如读锁 也就是共享锁。
使用{@code synchronized}方法或语句可以访问与每个对象关联的隐式监视器锁,但是强制所有锁的获取和释放都以块结构的方式进行:当获取多个锁时,它们必须以相反的顺序释放,并且所有锁必须以相同的词法范围释放。
虽然{@code synchronized}方法和语句的作用域机制使得使用监视器锁进行编程更加容易,并且有助于避免许多涉及锁的常见编程错误,但是在某些情况下,您需要以更灵活的方式使用锁。例如,一些遍历并发访问的数据结构的算法需要使用“hand-over-hand”或“链锁”:先获取节点A的锁,再获取节点B的锁,然后释放A,获取C,再释放B,获取D等。{@code Lock}接口的实现允许在不同的范围内获取和释放一个锁,并允许以任意顺序获取和释放多个锁,从而支持使用这些技术。
这种灵活性的增加带来了额外的责任。块结构锁的缺失消除了使用{@code synchronized}方法和语句时发生的锁的自动释放。在大多数情况下,应该使用以下习语:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}}
当锁定和解锁发生在不同的作用域时,必须注意确保持有锁时执行的所有代码都受到try-finally或try-catch的保护,以确保在必要时释放锁。
Lock实现提供另外功能的使用{}@code同步方法和语句通过提供一个非阻塞试图获得一个锁({@link # tryLock()}),试图获得锁,可以打断({@link # lockInterruptibly},试图获得锁,可以超时({@link # tryLock(长,TimeUnit)})。
Lock类还可以提供与隐式监视器锁完全不同的行为和语义,如保证顺序、不可重入使用或死锁检测。如果实现提供了这种专门的语义,那么实现必须记录这些语义。
注意,{@code Lock}实例只是普通对象,它们本身可以用作{@code synchronized}语句中的目标。获取{@code lock}实例的监视器锁与调用该实例的{@link #lock}方法没有指定的关系。为了避免混淆,建议您永远不要以这种方式使用{@code Lock}实例,除非在它们自己的实现中。
除非特别说明,为任何参数传递一个null值都会导致抛出NullPointerException。
所有的“锁”实现都必须执行内置monitorlock提供的相同的内存同步语义,如Java&trade的第17章所述;语言规范:成功的锁操作与成功的锁操作具有相同的内存同步效果。成功的{@code unlock}操作与成功的unlock操作具有相同的内存同步效果。
不成功的锁定和解锁操作以及重入锁定/和解锁操作不需要任何内存同步效果。
三种形式的锁获取(可中断、不可中断 限时)在性能特征、顺序保证或其他实现方面可能有所不同。此外,在给定的{@code lock}类中可能无法中断正在进行的获取锁的能力。因此,实现不需要为所有三种形式的锁获取定义完全相同的保证或语义,也不需要支持正在进行的锁获取的中断。需要一个实现来清楚地记录每个锁定方法提供的语义和保证。它还必须遵守这个接口中定义的中断语义,前提是支持锁获取的中断:要么完全支持,要么只支持方法入口。
由于中断通常意味着取消,而且对中断的检查通常不频繁,所以实现可能更倾向于响应中断,而不是正常的方法返回。即使可以显示在另一个操作之后发生的中断可能已经解除了线程阻塞,这也是正确的。实现应该记录这种行为。
接口结构








网友评论