JDK7中Lock源码概述

来源:互联网 发布:mysql如何删除数据库 编辑:程序博客网 时间:2024/06/07 11:59
Lock是java.util.concurrent.locks的接口,其所有已知实现类有:ReentrantLock,ReentrantReadWriteLock.ReadLock, 
ReentrantReadWriteLock.WriteLock。

Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的Condition对象。

锁是控制多个线程对共享资源进行访问的工具。通常锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过某些锁可能允许对共享资源并发访问,如ReadWriteLock的读取锁。

synchronized方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。

虽然synchronized方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如某些遍历并发访问的数据结果的算法要求使用"hand-over-hand"或"chain locking":获取节点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实现都必须实施与内置监视器锁提供的相同内存同步语义:
成功的lock操作与成功的Lock操作具有同样的内存同步效应。
成功的unlock操作与成功的Unlock操作具有同样的内存同步效应。
不成功的锁定与取消锁定操作以及重入锁定/取消锁定操作都不需要任何内存同步效果。

实现注意事项
三种形式的锁获取(可中断、不可中断和定时)在其性能特征、排序保证或其它实现质量上可能会有所不同。而且对于给定的Lock类,可能没有中断正在进行的锁获取的能力。因此并不要求实现为所有三种形式的锁获取定义相同的保证或语义,也不要求其支持中断正在进行的锁获取。实现必需清楚地对每个锁定方法所提供的语义和保证进行记录。还必须遵守此接口中定义的中断语义,以便为锁获取中断提供支持:完全支持中断或仅在进入方法时支持中断。由于中断通常意味着取消,而通常又很少进行中断检查,因此相对于普通方法返回而言,实现可能更喜欢响应某个中断。即使出现在另一个操作后的中断可能会释放线程锁时也是如此。实现应记录此行为。


Lock提供的方法不多,具体说明如下:

void lock()
获取锁,如果锁不可用,出于线程调度目的将禁用当前线程,并且在获得锁之前该线程将一直处于休眠状态。
实现注意事项:
Lock实现可能能够检测到锁的错误使用,比如会导致死锁的调用,在那种环境下还可能抛出一个(unchecked)异常。Lock实现必须对环境和异常类型进行记录。

void lockInterruptibly() throws InterruptedException
如果当前线程未被中断则获取锁。如果锁可用则获取锁并立即返回。
如果锁不可用,出于线程调度目的将禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
(1)锁由当前线程获得;
(2)其它某个线程中断当前线程,并且支持对锁获取的中断。
如果当前线程:
在进入此方法时已经设置了该线程的中断状态或者在获取锁时被中断,并且支持对锁获取的中断,则将抛出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。

boolean tryLock(long time,TimeUnit unit)throws InterruptedException
如果锁在给定的等待时间内空闲,并且当前线程未被中断则获取锁。如果锁可用则此方法将立即返回值true。如果锁不可用,出于线程调度目的将禁用当前线程,并且在发生以下三种情况之一前,该线程将一直处于休眠状态:
(1)锁由当前线程获得;
(2)其它某个线程中断当前线程,并且支持对锁获取的中断;
(3)已超过指定的等待时间
如果获得了锁则返回值true。如果当前线程在进入此方法时已经设置了该线程的中断状态或者在获取锁时被中断,并且支持对锁获取的中断,则将抛出InterruptedException,并会清除当前线程的已中断状态。如果超过了指定的等待时间则将返回值false。如果time小于等于0,该方法将完全不等待。
实现注意事项:
在某些实现中可能无法中断锁获取,即使可能该操作的开销也很大。程序员应该知道可能会发生这种情况。在这种情况下该实现应该对此进行记录。
相对于普通方法返回而言,实现可能更喜欢响应某个中断或者报告出现超时情况。
Lock实现可能可以检测锁的错误用法,例如某个调用可能导致死锁,在特定的环境中可能抛出(未经检查的)异常。该Lock实现必须对环境和异常类型进行记录。
参数:
time-等待锁的最长时间
unit-time参数的时间单位
返回:
如果获得了锁,则返回true;如果在获取锁前超过了等待时间,则返回false
抛出:
InterruptedException-如果在获取锁时,当前线程被中断(并且支持对锁获取的中断)

void unlock()释放锁。
实现注意事项:Lock实现通常对哪个线程可以释放锁施加了限制(通常只有锁的保持者可以释放它),如果违背了这个限制,可能会抛出(未经检查的)异常。该Lock实现必须对所有限制和异常类型进行记录。

Condition newCondition()
返回绑定到此Lock实例的新Condition实例。在等待条件前,锁必须由当前线程保持。调用Condition.await()将在等待前以原子方式释放锁,并在等待返回前重新获取锁。
实现注意事项:Condition实例的具体操作依赖于Lock实现,并且该实现必须对此加以记录。
返回:用于此Lock实例的新Condition实例
抛出:UnsupportedOperationException-如果此Lock实现不支持条件
原创粉丝点击