承接上篇JUC之AbstractQueuedSynchronizer 我们分析一下最常用的锁 ReentrantLock,即可重入锁。
上篇我们分析了aqs的acquire方法和release方法。接下来我们分析ReentrantLock是如何通过aqs实现锁的。
先看一下锁的定义。
public interface Lock {
/**
* 加锁,如果获取不到锁会阻塞当前线程
*/
void lock();
/**
* 加锁,如果获取不到锁会阻塞当前线程和lock方法不同的是,锁阻塞期间会被中断
*/
void lockInterruptibly() throws InterruptedException;
/**
* 尝试加锁,没有抢到锁时会返回false,反之,返回true
*/
boolean tryLock();
/**
* 尝试加锁,成功返回true;失败,阻塞并尝试加锁,超时返回false,否则加锁成功返回true
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* 解锁
*/
void unlock();
/**
* 返回和锁绑定的Condition对象
*/
Condition newCondition();
}
这里ReentrantLock的用法不再细说,我们看ReentrantLock是如何实现的。
ReentrantLock仅持有了一个Sync类型的变量 sync,所有锁的方法的实现都是通过sync提供的方法来实现的。
ReentrantLock核心方法:
public void lock() {
sync.lock();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public int getHoldCount() {
return sync.getHoldCount();
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public boolean isLocked() {
return sync.isLocked();
}
public final boolean isFair() {
return sync instanceof FairSync;
}
protected Thread getOwner() {
return sync.getOwner();
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
public final int getQueueLength() {
return sync.getQueueLength();
}
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
而Sync是ReentrantLock的内部类,继承与aqs,同样是抽象类。
Sync的实现类同样是内部类,有两个NonfairSync和FairSync,不公平和公平的同步器。
具体使用哪个同步器,是通过ReentrantLock的构造函数传入的boolean类型的入参fair来决定的。默认使用的是非公平的同步器。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
为什么默认使用非公平的同步器?是因为非公平的同步器效率更高,具体下面分析。
我们来看一下Sync的实现
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* 提供了一个抽象方法,交由子类实现
*/
abstract void lock();
/**
* 非公平的尝试获取锁,这里涉及到了设置获得锁的线程,以及state,都是aqs提供的方法。
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取当前的state
int c = getState();
//表示没有线程获取到锁
if (c == 0) {
//设置锁的状态,成功即表示当前线程持有锁
if (compareAndSetState(0, acquires)) {
//设置持有所得线程为当前线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果当前线程已经持有锁了
else if (current == getExclusiveOwnerThread()) {
//将状态值累加
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
/**
* 尝试释放锁
*/
protected final boolean tryRelease(int releases) {
//状态值减去需要释放的数量
int c = getState() - releases;
//不是获得锁的线程尝试释放锁,将会抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
//把获得锁的线程置为null
setExclusiveOwnerThread(null);
}
//设置锁的状态,因为同时只会有一个线程执行到这里,所以不需要利用cas操作保证线程安全。
setState(c);
return free;
}
/**
* 是不是当前线程独占
*/
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
/**
* 生成Condtion对象
*/
final ConditionObject newCondition() {
return new ConditionObject();
}
/**
* 当前线程是不是当前锁的持有线程
*/
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
/**
* 持有的状态值
*/
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
/**
* 是否有线程获得锁
*/
final boolean isLocked() {
return getState() != 0;
}
/**
* 反序列化锁,将锁的转态置为0
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
Sync代码比较简单,接下来我们来看NonfairSync和FairSync,主要关注是如何实现非公平和公平的。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
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() {
//和NonfairSync对比,没有尝试设置状态
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 如果队列中没有等待的线程,才会尝试设置状态。假如队列中有别的线程在等待,将会返回false,之后的方法会把当前线程加入到等待的队列。这是和NonfairSync的区别。
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
ReentranLock的实现比较简单,主要是通过Sync来实现锁的方法,其中最核心的方法是tryAcquire()和tryRelease()方法,有了这两个方法结合aqs提供的方法,我们就可以实现一个完整的锁。
下一篇我们将会分析ReentrantLock的lockInterruptibly(),tryLock(long timeout, TimeUnit unit)和newCondition()方法。