在Java 1.5之前,协调对共享对象的访问可以使用的机制只有synchronized
和volatile
两种。Java1.5增加了一种新的机制:ReentrantLock
。但ReentrantLock
并不是替代内置加锁的方法,而是当内置加锁机制不适用时,作为一种可选择的高级功能。
1、Lock与ReentrantLock
lock
是一个接口,定义了一组抽象的加锁操作。与synchronized
不同的是,lock
提供了一种无条件的、可轮询的、定时的以及可中断的锁的获取操作,下面来看lock
接口的源码、
public interface Lock {
//获得锁,如果锁定不可用,则当前线程将被禁用以进行线程调度,并且在此之前处于休眠状态。
void lock();
//如果当前线程未被中断,则获取锁。如果锁可用,则获取锁,并立即返回。可中断锁获取操作的实现
void lockInterruptibly() throws InterruptedException;
//仅在调用时锁为空闲状态才获取该锁。通常对于那些不是必须获取锁的操作可能有用。轮询锁及可定时锁获取操作的实现。
boolean tryLock();
//若锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。轮询锁及可定时锁获取操作的实现。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁。对应于lock()、tryLock()、tryLock(xx)、lockInterruptibly()等操作,如果成功的话应该对应着一个unlock(),这样可以避免死锁或者资源浪费。
void unlock();
//返回绑定到此 Lock 实例的新 Condition 实例。
Condition newCondition();
}
ReentrantLock
实现了lock
接口,它提供了与synchronized
相同的互斥性、内存可见性及可重入的加锁语义,在加锁与释放锁时也与synchronized
有相同的内存语义。下面来看ReentrantLock
的实现。
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
//基于AQS实现的同步机制
abstract static class Sync extends AbstractQueuedSynchronizer {
...
}
//非公平锁的实现,默认是非公平锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//公平锁的实现
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(