/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
从构造函数可以看出,可以指定是否公平,true构建公平锁,false构建非公平锁。默认是非公平锁。
-
- 公平锁:AbstractQueuedSynchronizer.tryAquire()的实现会考虑到等待队列。
- 非公平锁:AbstractQueuedSynchronizer.tryAquire()的实现不考虑等待队列。
- ReentrantLock的锁功能的核心Sync类
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
这个Sync是继承了AbstractQueuedSynchronizer的内部抽象类,主要由它负责实现锁的功能。AbstractQueuedSynchronizer内部存在一个获取锁的等待队列及其互斥锁状态下的int状态位(0当前没有线程持有该锁、n存在某线程重入锁n次)即可,该状态位也可用于其它诸如共享锁、信号量等功能。
Sync在ReentrantLock中有两种实现类:NonfairSync、FairSync,正好对应了ReentrantLock的非公平锁、公平锁两大类型。
下图就是unfairLock.lock()函数内部逻辑流程图,fairLock.lock()内部逻辑类似。
首先,ReentrantLock的lock()方法会调用其内部成员变量sync的lock()方法;
其次,sync的非公平锁NonfairSync或公平锁FairSync实现了父类AbstractQueuedSynchronizer的lock()方法,其会调用acquire()方法;
然后,acquire()方法则在sync父类AbstractQueuedSynchronizer中实现,它只有一段代码:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
通过tryAcquire()方法试图获取锁,获取到直接返回结果,否则通过嵌套调用acquireQueued()、addWaiter()方法将请求获取锁的线程加入等待队列,如果成功的话,将当前请求线程阻塞。
上述就是公平锁、非公平锁实现获取锁的主要流程,而针对每种锁来说,其实现方式有很大差别,主要就体现在各自实现类的lock()和tryAcquire()方法中。在sync的抽象类Sync及其抽象父类AbstractQueuedSynchronizer中,lock()方法和tryAcquire()方法被定义为抽象方法或者未实现,而是由具体子类去实现。
/**
* 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);
}
通过代码可以看到,非公平锁上来就无视等待队列的存在而抢占锁,通过基于CAS操作的compareAndSetState(0, 1)方法,试图修改当前锁的状态,这个0表示AbstractQueuedSynchronizer内部的一种状态,针对互斥锁则是尚未有线程持有该锁,而>=1则表示存在线程持有该锁,并重入对应次数,这个上来就CAS的操作也是非公共锁的一种体现,CAS操作成功的话,则将当前线程设置为该锁的唯一拥有者。
这里对于CAS再多说两句,0代表lock没有被持有,而这里第一个参数为0,就代表期望lock没被持有,如果compareAndSet()函数返回true,就代表这个假设正确,那么我们就可以获得这个锁。并将状态设为1,代表lock被持有了一次。
抢占不成功的话,则调用父类的acquire()方法,按照上面讲的,继而会调用tryAcquire()方法,这个方法也是由最终实现类NonfairSync实现的,如下:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
而这个nonfairTryAcquire()方法实现如下:
/**
* Performs non-fair tryLock. tryAcquire is
* implemented in subclasses, but both need nonfair
* try for trylock method.
*/
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;
}
这里getState()返回值代表这个lock被reentrant持有的次数。
还是上来先判断锁的状态,通过CAS来抢占,抢占成功,直接返回true,如果锁的持有者线程为当前线程的话,则通过累加状态标识重入次数。抢占不成功,或者锁的本身持有者不是当前线程,则返回false,继而后续通过进入等待队列的方式排队获取锁。可以通过以下简单的图来理解:
总的来说公平锁的lock方法会先判断等待队列里是否有线程,如果有先给等待队列里的第一个线程分配锁,并将当前主动请求lock的线程加入到等待队列尾。
final void lock() {
acquire(1);
}
可以看出,公平锁不需要调用compareAndSet(),直接调用acquire(),acquire会最终调用fairTryAcquire
/**
* 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;
}
当前线程会在得到当前锁状态为0,即没有线程持有该锁,并且通过!hasQueuedPredecessors()判断当前等待队列没有前继线程(也就是说,没有比我优先级更高的线程在请求锁了)获取锁的情况下,通过CAS抢占锁,并设置自己为锁的当前拥有者,当然,如果是重入的话,和非公平锁处理一样,通过累加状态位标记重入次数。
而一旦等待队列中有等待者,或当前线程抢占锁失败,则它会乖乖的进入等待队列排队等待。公平锁的实现大致如下: