Java5.0增加了一种新的机制:ReentrantLock。当内置加锁机制不适应时,ReentrantLock作为一种可选择的高级功能。
Lock与ReentrantLock
Lock提供了一种无条件的、可轮训的、定时的以及可中断的锁获取操作,所有的加锁和解锁的方式都是显示的。
Lock 的接口定义:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
ReentrantLock实现了Lock接口,与synchronized一样,提供了可重入的加锁语句。ReentrantLock支持在Lock接口中定义的所有获取锁模式,与synchronized相比,它还为处理锁的不可用性问题提供了更高的灵活性。
使用ReentrantLock来保护对象状态:
Lock lock = new ReentrantLock();
lock.lock();
try {
..........
}finally {
lock.unlock();
}
轮询锁与定时锁
在内置锁中,死锁是一个严重的问题,恢复程序的唯一方法是重新启动程序,而防止死锁的唯一方法就是在构造程序时避免出现不一致的锁顺序。可定时的与可轮询的锁提供了另一种选择:避免死锁的发生。
可定时的与可轮询的锁获取方式是由tryLock方法实现的。
/** Acquires the lock only if it is not held by another thread at the time of invocation. */
public boolean tryLock(){}
/**Acquires the lock if it is not held by another thread within the given waiting time and the current thread has not been interrupted*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException{}
可定时的与可轮询的锁获取方式,它会释放已经获得的锁,然后重新尝试获取所有锁(或者至少会将这个失败记录到日志,并采取其他措施)。
通过tryLock来避免顺序死锁:
if (fromAcct.lock.tryLock()){
try{
if (toAcct.lock.tryLock()){
try{
.............
}finally {
toAcct.lock.unlock();
}
}
}finally {
fromAcct.lock.unlock();
}
}
如上代码,使用tryLock来获取两个锁,如果不能同时获得,那么回退并重新尝试。
在实现具有时间限制的操作时,定时锁同样非常有用。
当在带有时间限制的操作中调用了一个阻塞方法时,它能根据剩余时间来提供一个时限。如果操作不能在指定时间内给出结果,那么程序就会提前结束。
带有时间限制的加锁:
if (!lock.tryLock(3000, TimeUnit.SECONDS)){
return false;
}
try {
return true;
}finally {
lock.unlock();
}
可中断的锁获取操作
正如定时的锁获取操作能在带有时间限制的操作中使用独占锁,可中断的锁获取操作同样能在可取消的操作中使用加锁。
lockInterruptibly方法能够在获得锁的同时保持对中断的响应,并且由于它包含在Lock中,因此无须创建其他类型的不可中断阻塞机制。
/*Acquires the lock unless the current thread is interrupted*/
void lockInterruptibly() throws InterruptedException;
可中断的锁的获取操作
lock.lockInterruptibly();
try {
return cancel();
}finally {
lock.unlock();
}
public boolean cancel() throws InterruptedException{}