AQS 加锁流程源码解析
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description
* @Date 2021/3/11 16:07
* @Created by
*/
public class Test {
public static void main(String[] args) {
/**
* 默认非公平锁
*/
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
// do something...
} finally {
lock.unlock();
}
}
/**
* ReentrantLock lock = new ReentrantLock();
* AQS 获取锁流程
* @see java.util.concurrent.locks.AbstractQueuedSynchronizer
* @see ReentrantLock.FairSync 公平锁
* 1、先判断是否有现成在排队,如果有,直接进等待队列
* {@link java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire(int)} hasQueuedPredecessors
*
* @see ReentrantLock.NonfairSync 非公平锁
* 1、先尝试获取锁,能获取到则直接执行
* {@link ReentrantLock.Sync#nonfairTryAcquire(int)} compareAndSetState
* <pre> {@code
* 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()) {
* // 如果当前拥有锁的线程是自己,则将state+1(可重入锁)
* int nextc = c + acquires;
* if (nextc < 0) // overflow
* throw new Error("Maximum lock count exceeded");
* setState(nextc);
* return true;
* }
* return false;
* }
* }
* <pre/>
* 2、若没有获取到锁,则加入到等待队列
* {@link AbstractQueuedSynchronizer#acquire(int)} addWaiter(Node.EXCLUSIVE), arg) 加入等待队列
* <pre>{@code
* // 自旋,知道当前线程加入等待队列
* 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;
* }
* }
* // 若加入队列失败,则进入
* {@link AbstractQueuedSynchronizer#enq(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node)}
* // 知道加入队列成功为止
* 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)) {
* // 设置成功,再将之前尾节点的next指向当前节点
* t.next = node;
* // 返回之前的尾节点
* return t;
* }
* }
* }
* }
* }<pre/>
* 3、加入等待队列成功,再从队列取出线程,获取锁
* {@link AbstractQueuedSynchronizer#acquire(int)
* @link AbstractQueuedSynchronizer#acquireQueued(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int)
* } acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
* <pre>{@code
* // 自旋,知道当前线程获取锁
* final boolean acquireQueued(final Node node, int arg) {
* // 获取锁是否失败
* boolean failed = true;
* try {
* // 是否要中断当前线程
* boolean interrupted = false;
* for (;;) {
* // 获取当前线程节点的prev节点(不能为空,head节点为当前拥有锁的线程)
* final Node p = node.predecessor();
* // 当先线程prev节点为当前拥有锁的线程,则当前线程再次尝试获取锁
* if (p == head && tryAcquire(arg)) {
* // 当前线程获取锁成功,则将当前线程设置为head节点
* setHead(node);
* // 原先head节点的next指向当前线程节点,释放该引用,以便GC
* p.next = null; // help GC
* // 获取锁成功
* failed = false;
* // 无需中断当前线程
* return interrupted;
* }
* // 当前线程prev节点不是head节点,或者当前线程没有获取到锁
* // 判断当前线程prev指向的节点waitStatus=SIGNAL,说明后面的线程需要取消
* if (shouldParkAfterFailedAcquire(p, node) &&
* parkAndCheckInterrupt())
* interrupted = true;
* }
* } finally {
* if (failed)
* cancelAcquire(node);
* }
* }
* }<pre/>
*/
}