ReentrantLock是基于AQS(AbstractQueuedSynchronizer)来进行实现的,分为公平锁和非公平锁,可以通过在构造器中出入true将ReentrantLock设置为一个公平锁。
AQS是一个FIFO的双向队列,自内部通过节点head、tail记录队首和队尾元素,队列元素的类型为Node,其中Node中thread变量用来存放进入AQS队列里面的线程,Node节点内部的SHARED用来标记该线程是获取共享资源而被阻塞挂起后放入AQS队列中的,EXCLUSIVE用来标记线程是获取独占资源时被官气后放入AQS队列中的,waitStatus记录当前线程等待状态,可以为CANCELLED(线程被取消了)、SIGNAL(线程需要被唤醒)、CONDITION(线程在条件队列里面等待)、PROPAGATE(释放共享资源时需要通知其他节点);prev记录当前节点的前驱节点,next记录当前节点的后继节点。
对于ReentrantLock来说,AQS的state 用来记录当前线程获取锁的可重入次数,不同工具类有不同的含义,例如读写锁ReentrantReadWriteLock 将state的高16位表示读状态,也就是获取该锁的读的次数,低16位表示获取到写锁的线程的可重入次数
AQS也是主要提供了4个方法,分别为:tryAcquire、tryAcquireShared、tryRelease、tryReleaseShared 分别供子类实现
下面主要讲下 ReentrantLock主要逻辑:
非公平锁
1、new ReentrantLock() 创建一个非公平锁,内部实现是创建了一个名称为sync的内部类NonfairSync
public ReentrantLock(boolean fair) {
//fair为true表示公平锁,false为表示非公平锁
sync = fair ? new FairSync() : new NonfairSync();
}
2、调用ReentrantLock的lock方法,内部调用sync的lock方法,方法语义为:将AQS的state由0通过cas更改为1
public void lock() {
sync.lock();
}
final void lock() {
//尝试cas更新state状态
if (compareAndSetState(0, 1))
...
else
....
}
3、第二步成功的话,将AQS中的独占线程exclusiveOwnerThread设置为自己
final void lock() {
if (compareAndSetState(0, 1))
//如下代码,将AQS中的独占线程设置为自己
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
4、第二步失败的话,调用AQS的acquire方法即独占锁获取方法,获取一个资源
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//如下代码,调用AQS的acquire方法
acquire(1);
}
5、继续调用ReentrantLock中nonfairTryAcquire方法即非公平锁获取实现
public final void acquire(int arg) {
//如下代码,此处tryAcquire为 ReentrantLock的NonfairSync非公平模式的方法实现
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
6、方法内部语义为:获取state状态,如果等于0 则尝试更改为1,并设置独占线程标识
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()) {
...
}
return false;
}
7、否则在判断独占锁标识是否为自己,如果是 则重入并将state增1
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;
}
8、都不成功则进行接下来的操作
9、新增节点,将当前线程为参数创建新节点,加入到链表尾部
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
//如下代码 中的 addWaiter方法
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
10、调用AQS的acquireQueued方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
//如下代码 中的 acquireQueued方法
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
11、在方法内部进行循环,通过新加进来的节点获取前一个节点
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//循环
for (;;) {
//如下代码
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
12、如果前一个节点是头节点,则尝试调用tryAcquire方法获取锁,获取成功后将自己设置为头结点,并移除节点内部关联的线程属性
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
13、如果不是头节点或者获取锁失败的话,则尝试修改节点状态waitStatus 并 将自己的线程阻塞
//方法:shouldParkAfterFailedAcquire修改状态、parkAndCheckInterrupt阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
14、因为是循环,最后将所有标志为取消状态的节点移除,将其他状态的修改为等待状态。但是 由13步可知,每个后继节点只负责将自己的前驱节点修改状态,因为 修改成功后 自己线程就被阻塞了,等待唤醒。
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
公平锁
对于公平锁来说,其与非公平锁的区别在于 公平锁没有第三步,直接就是第四步 acquire方法调用,并且 acquire方法中 的 tryAcquire方法实现是公平锁的实现方式,
protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取AQS中的state状态值
int c = getState();
//如果等于0
if (c == 0) {
//通过 hasQueuedPredecessors方法 判断 阻塞队列 head头节点的下一个节点是否为当前线程的节点
if (!hasQueuedPredecessors() &&
//尝试修改state的状态为1
compareAndSetState(0, acquires)) {
//以上两个条件都满足的话 则将AQS中的独占线程 设置为自己
setExclusiveOwnerThread(current);
return true;
}
}
//否则通过getExclusiveOwnerThread方法获取AQS中的独占线程,并判断是否为自己当前线程
else if (current == getExclusiveOwnerThread()) {
//是的话,将 state + 1
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//将state的值刷新到主内存中
setState(nextc);
return true;
}
return false;
}