ReentrantLock是concurrent包中,实现的一个锁,下面,我们将对其源码进行分析,以期获得更为有价值的内容。
我们可以按照ReentrantLock的使用方式,来慢慢解析其源码构成。
正如上一章Java多线程随手记——各种锁中的CODE使用的方式,首先我们需要初始化ReentrantLock对象。
/**
* 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();
}
从这里可以看到,ReentrantLock实现了公平锁和非公平锁两种方式,首先,我们先把两种实现的思路描述下,然后再看具体实现。
公平锁:看名字就特别和谐,大家都一起排队WC,队伍中轮到谁了谁就去。
非公平锁:这就是特别暴力了,大家都憋不住,队伍排是排,但是只要厕所里的人一出来,不管队伍顺序,靠拳头说话,谁抢到了算谁的。
接下来,我们开始着手具体实现。
公平锁:
/**
* 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 (isFirst(current) &&
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;
}
首先,看看state是否为0,也就是占用线程已经全部unlock掉,那么再看看自己是不是处于队列的第一个,compareAndSetState()同时检查占用状态,并且修改state值(这是一个底层的CAS原子操作,我是把它理解为类似操作系统中的P操作)。current == getExclusiveOwnerThread()后面便是完成了可重入锁的功效了,当前线程进入lock再这之上再加锁+acquires,之后的章节会详细介绍可重入锁的用途。
非公平锁:
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;
}
这个非公平锁就野蛮的很,只要看到C为0了,就开抢,不管自己队列顺序,直接做CAS操作,谁先抢到谁就把state这门给关了,让别人进不来。
下面,我们回头看看调用tryAcquire 的acquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
可以看到不管公平锁还是非公平锁,都是如果无法获取到当前锁,那么将进入队列中,同时如果满足阻塞条件,那么该线程将会被interrupt掉,直到等待被唤醒。
AbstractQueuedSynchronized 这个类的实现还是挺复杂的,同时它为了该Queue可以并发使用了一个双重检测的设计,打算新开个章节来详细叙述。
下一章节:AbstractQueuedSynchronized类源码分析