一.参考
二.架构
AQS的成员变量,Node类型的head,tail,实现队列的FIFO操作;state记录队列的同步状态;exclusiveOwnerThread记录当前持有锁的线程.
三.源码细节
ReentrantLock内部通过AQS实现,以ReentrantLock的lock,unlock为测试用例.
(一)lock加锁操作,代码如下:
final void lock() {
//通过Unsafe把state计数的修改为1,进行加锁.如果队列未加锁,state为0,可成功改为1
//如果队列已经被加过锁,state不为1,执行else部分,入队.
if (compareAndSetState(0, 1))
//加锁后,设置exclusiveOwnerThread为当前持有锁的线程
setExclusiveOwnerThread(Thread.currentThread());
else
//未持有锁的线程入队
acquire(1);
}
(二).AQS加锁
public final void acquire(int arg) {
//尝试获取锁.由AQS的子类实现.比如进入ReentrantLock的nonfairTryAcquire()方法
//tryAcquire获取不到锁时,addWaiter当前线程入队
//acquireQueued再一次尝试获取锁,获取不到作为队尾进入休眠
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
(三).非公平锁尝试加锁
final boolean nonfairTryAcquire(int acquires) {
//当前要获取锁的线程
final Thread current = Thread.currentThread();
//获取AQS锁的状态
int c = getState();
if (c == 0) {
//如果能拿到锁,修改锁状态计数
if (compareAndSetState(0, acquires)) {
//设置当前线程为拿到锁的线程
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//如果当前线程已经持有锁,说明重入了,ReentrantLock可以重入。修改锁的计数
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
(四).AQS入队
队列的头节点没有数据.可以认为代表当前持有锁的节点.第二个节点开始存等待的线程,是第一个等待锁的线程.这个是关键.
新进节点作为队尾进入休眠.
private Node addWaiter(Node mode) {
//创建一个入队的节点
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
//试着快速入队.即原有队列除了头结点外,有线程在等。直接加到队尾.
Node pred = tail;
if (pred != null) {
//新进节点的前驱设为原队列的尾节点
node.prev = pred;
if (compareAndSetTail(pred, node)) {
//原队列的尾节点的后继设置为新进节点
pred.next = node;
//返回新进来节点
return node;
}
}
enq(node);
return node;
}
(五).队列节点Node
成员有prev,next,thread,nextWaiter,是个双链表.
(六).再一次尝试获取锁,获取不到作为队尾进入休眠
入参为新进的节点,进来这里前已经将新进节点设为队尾.
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//注意第一次和第二次循环shouldParkAfterFailedAcquire的逻辑不同
for (;;) {
//获取当前节点的前驱节点
final Node p = node.predecessor();
//如果前驱节点是头结点,头结点没有线程数据。说明当前节点是第一个排队的线程.
//不断尝试获取锁,轮询等待当前持有锁的线程释放锁.调用unlock()后排队轮到自己
//进入ReentrantLock的nonfairTryAcquire()方法
if (p == head && tryAcquire(arg)) {
//获取到锁,把当前节点设置为头结点.node.thread和node.prev设置为null.
//这里可以看出头结点head不存在线程thread数据.
setHead(node);
//原来队列的头结点之前有next指向node,把前面这个next只为null。
//减少当前节点的引用,去掉可达性,这样后面当前线程释放锁时,node没有被引用
p.next = null; // help GC
failed = false;
//是否是被中断返回,因为获取到锁,不是下面sleep被中断的,返回false.
return interrupted;
}
//如果没有获取到锁,当前节点已经被加入队尾,进入park休眠状态,等待其他线程唤醒.
//shouldParkAfterFailedAcquire休眠前修改驱节点的状态
//根据前驱节点的状态判断当前节点是否进入休眠??
//parkAndCheckInterrupt调用native方法进入休眠,等待被unlock唤醒后才从这个方法返回
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
(七).休眠前修改驱节点的状态
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.
*/
//第一次循环进入这里,修改前驱为SIGNAL状态
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
(八).AbstractQueuedSynchronizer.release()释放锁.
ReentrantLock.unlock()进入这个方法进行解锁.
public final boolean release(int arg) {
//释放锁,返回锁计数是否被减为0,可以释放
if (tryRelease(arg)) {
//头结点没有线程。唤醒头结点后面的第一个等待线程
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
(九).ReentrantLock的尝试释放锁.
protected final boolean tryRelease(int releases) {
//减掉当前锁状态的计数
int c = getState() - releases;
//如果当前线程不是持有锁的线程抛出异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果当前锁的计数变为0,说明没有线程持有锁,锁的thread变量置位null
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
//修改锁技术为减掉之后的
setState(c);
//返回是否锁被释放
return free;
}
(十).唤醒头结点后面的第一个等待线程,传进来的为头结点引用
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
//等待中的线程默认是SIGNAL,-1
if (ws < 0)
//设置头结点的等在状态为0
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//获取头结点后面的第一个等待节点
Node s = node.next;
//获取后面等待线程中第一个状态waitStatus<=0的节点唤醒
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//唤醒线程
if (s != null)
LockSupport.unpark(s.thread);
}