对于ReentrantLock,一般我们在调用无参构造函数的时候,构造的是非公平锁,当前类也存在一种可以指定锁类型的构造方法,即 ReentrantLock(boolean fair),ReentrantLock锁的实现是通过内部类FairSync和NonfairSync继承AQS实现的。
我们今天主要讨论下这两个内部类,从而探讨下代码级别是如何实现公平锁和非公平锁的。
先看ReentrantLock加锁方法,可以自己去看源码,底层是在FairSync和NonfairSync这两个内部里面做的逻辑
不同的是,非公平锁在lock时,先调用底层的unsafe原生类的CAS方法,获取当前锁的机会,如果获取不成功则和公平锁一样调用acquire(1);
我们再来看acquire(1)方法,在AQS中实现如下:
会先执行tryAcquire方法,然后根据短路与看时候需要进行acquireQueued,acquireQueued方法是指当前线程未获得锁的情况下,将该线程加入等待的引用链中
贴上公平锁的tryAcquire方法实现
贴上非公平锁的tryAcquire方法实现
比较关键的差别是在hasQueuedPredecessors方法上,非公平锁不会调用该方法,公平锁中该方法的意思是检测当前线程是否为acquireQueued方法往head之后添加引用,如果是则利用CAS方法获得当前reentrantLock。
其实公平锁和非公平锁最大的差别就是在获取锁时,是否会去找当前头结点之后维护的等待队列。
我们今天主要讨论下这两个内部类,从而探讨下代码级别是如何实现公平锁和非公平锁的。
先看ReentrantLock加锁方法,可以自己去看源码,底层是在FairSync和NonfairSync这两个内部里面做的逻辑
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(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;
}
}
不同的是,非公平锁在lock时,先调用底层的unsafe原生类的CAS方法,获取当前锁的机会,如果获取不成功则和公平锁一样调用acquire(1);
我们再来看acquire(1)方法,在AQS中实现如下:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
会先执行tryAcquire方法,然后根据短路与看时候需要进行acquireQueued,acquireQueued方法是指当前线程未获得锁的情况下,将该线程加入等待的引用链中
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;
}
贴上公平锁的tryAcquire方法实现
final boolean nonfairTryAcquire(int acquires) {
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;
}
贴上非公平锁的tryAcquire方法实现
比较关键的差别是在hasQueuedPredecessors方法上,非公平锁不会调用该方法,公平锁中该方法的意思是检测当前线程是否为acquireQueued方法往head之后添加引用,如果是则利用CAS方法获得当前reentrantLock。
其实公平锁和非公平锁最大的差别就是在获取锁时,是否会去找当前头结点之后维护的等待队列。