昨天讲完了AQS,今天来看看实现吧。先准备介绍ReentrantLock,剩下的之后再介绍。
有了之前AQS的基础,再来看这些实现,真的是简单的不行,主要是我们来学习这种很牛的思想,对我们的编码水平是一个很大幅度的跨越。好了,话不多说,速来讲解,哈哈哈。
整体结构预览
打开ReentrantLock的源码,直接就发现了一个Sync类继承了我们之前的讲解的AQS,在这里他实现了我们AQS独占锁的非公平获取(nonfairTryAcquire)和释放资源state(release)的逻辑。
但是我们发现Sync还是一个抽象类,具体的是被FairSync和NonfairSync给继承了。那么具体的两个实现类是干啥的呢,ReentrantLock他是支持公平锁和非公平锁的,所以他的架构是这样。那么什么是公平锁和非公平锁呢,如果线程访问顺序和资源获取顺序是一致的,那他就是公平的,如果不一致那就是非公平的,比如现在A,B入队了,现在来了一个C,他直接插队到AB前面去了,那就是非公平的了。
NonfairSync中,我们见到了久违的tryAcquire获取资源,以及一个Sync类的抽象方法lock。
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
FairSync中,我们也看到了tryAcquire,以及lock。
final void lock() {
acquire(1);
}
你把他俩的lock方法一对比,就看出了确实他们是非公平和公平的了。NonfairSync中的lock,他多了一个if,如果现在队列中已经有AB了,那么假如A现在获取了资源,然后释放,state为0,再即将唤醒B的时候,C来了,他直接执行if成立,插队成功,B大喊这不公平!!!
构造方法
而在构造方法中,我们可以看到他默认的是非公平锁。
而为啥默认是非公平锁呢?在多数场景中,非公平锁的并发度确实比公平锁的高。
注:图片来自《Java并发编程的艺术》
NonFairSync
获取锁
ReentrentLock.lock()->Sync.lock()->NonFairSync.lock()->tryAcquire()->nonfairTryAcquire()
final void lock() {
if (compareAndSetState(0, 1))//不公平
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);//顶层AQS的逻辑
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);//适配器
}
final boolean nonfairTryAcquire(int acquires) {//非公平的tryAcquire
final Thread current = Thread.currentThread();
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;
}
加入来了三个线程ABC,假设A抢到了锁,BC线程再执行lock里面的if就不行了,走的else,然后尝试获取获取资源,发现不得行,返回了false。然后就被顶层的队列管理大哥AQS给入队了。嘶,AQS你也太棒了吧!
释放锁
ReentrantLock.unlock()->AQS.release()->AQS.tryRelease()->Sync.tryRelease()
public void unlock() {
sync.release(1);
}
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;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
哈哈哈,看完了AQS之后,确实挺简单的。别人问你RenntrantLock怎么实现非公平的啊?他让插队!
FairSync
而公平锁,就是在lock中没有添加if的条件,不让插队。其他的内容相差不大
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
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;
}
总结
公平锁和非公平锁,其他的大部分内容还是复用AQS的。