lock
final void lock() {
//当state的值是0的时候,就不会涉及到队列的问题,仅仅只是队state值的改变和owner的设置
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//失败进行抢占
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//非公平锁的抢占方式
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取状态量
int c = getState();
//装填量为0 可以抢占
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;
}
//入阻塞队列
private Node addWaiter(Node mode) {
//新建节点
Node node = new Node(Thread.currentThread(), mode);
//尾插法
Node pred = tail;
if (pred != null) {
//先指向前驱节点 再通过cas的方式从新设置尾节点
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//到这一步失败的原因是 阻塞队列为空 或者 cas设置尾结点失败
enq(node);
return node;
}
//兜底的入队方式
private Node enq(final Node node) {
//要么成功 要么我就一直不停
for (;;) {
Node t = tail;
//如果是队列为空,那么就新建队列,并且设置为 头节点
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
//常规尾插入队,要么成功 要么循环不停止
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//以独占的方式获取队列
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);
}
}
//这个函数的主要作用是 更新状态量
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;
}
分享和记录一个大佬写的笔记:
https://funzzz.fun/2021/05/13/AQS%E8%AF%A6%E8%A7%A3/