AQS 加锁流程源码解析

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/>
     */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值