compareAndSetState,这个方法在前面提到过了,再简单讲解一下,通过 CAS 算法去改变 state 的值,而这个 state 是什么呢? 在 AQS 中存在一个变量 state ,对于ReentrantLock 来说,假如 state = 0 表示无锁状态、假如 state > 0 表示有锁状态。 ( state 在不同的锁里边表达的意思是不一样的 )
所以在这里,是表示当前的 state 假如等于 0 ,则替换为 1 ,假如替换成功表示获取锁成功了由于 ReentrantLock 是可重入锁,所以持有锁的线程可以多次加锁,经过判断加锁线程就是当前持有锁的线程时
(即 exclusiveOwnerThread==Thread.currentThread() ),即可加锁,每次加锁都会将 state 的值 +1 , state 等于几,就代表当前持有锁的线程加了几次锁;
解锁时每解一次锁就会将 state 减 1 , state 减到 0 后,锁就被释放掉,这时其他线程可以加锁;
AbstractQueuedSynchronizer.acquire
假如 CAS 操作未能成功,阐明 state 已经不为 0 ,此时继续 acquire(1) 操作, acquire 是AQS中的方法 当多个线程同时进入这个方法时,首先通过 CAS 去修改 state 的状态,假如修改成功表示竞争锁成功,竞争失败的, tryAcquire 会返回 false
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
if (ws > 0) {// 如果前继节点是“取消”状态,则设置 “当前节点”的 “当前前继节点” 为 “‘原前继节点'的前继节点”。
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else { // 如果前继节点为“0”或者“共享锁”状态,则设置前继节点为SIGNAL状态。
/*
* 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;
}
复制代码
解读:假如有t1,t2两个线程都加入到了链表中
img
假如head节点位置的线程一直持有锁,那么t1和t2就是挂起状态,而HEAD以及Thread1的awaitStatus都是 SIGNAL ,在多次实验获取锁失败以后,就会通过下面的方法进行挂起(这个地方就是制止了惊群效应,每个节点只需要关心上一个节点的状态即可)