美文网首页
2021-08-11_AQS6个核心操作图解总结

2021-08-11_AQS6个核心操作图解总结

作者: kikop | 来源:发表于2021-08-11 16:48 被阅读0次

    20210811_AQS6个核心操作图解总结

    1概述

    1.1流程时序

    抢锁-->抢锁失败入队-->Park阻塞-->放弃入队即出队-->任务完成,释放锁-->唤醒同步队列中的兄弟。

    1.2核心6个操作

    1.2.1抢锁

    // 非公平锁
    final void lock() {
                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();
        }
    
    

    首先,看锁标志位state(默认0),T1线程抢到锁,则基于CAS机制修改标志位,设置独占线程,如下图:

    image-20210811154659834.png

    其次,又有线程T2来抢锁

    1. 是自己锁的线程T1,则是重入,计重入次数+1
    2. 是其他线程T2,抢锁失败,则进行入队,具体如1.2.2。
    3. 公平锁判断依据:hasQueuedPredecessors,看等待区有没有人

    1.2.2入队

    这里,waitStatus:我们陈之为闹钟。为唤醒使用,CLH算法(效率高,能充分利用cpu),默认0(初始状态)-->1(取消)-->-1(可以唤醒下一个了)

    普通队列特点:线程1顺利抢到锁,第一个节点则为线程2节点。(第一个线程执行,第二个线程放入队列,所以队列中节点1对应线程1节点

    AQS队列特点:第一个节点为空节点,第二个节点才为入队的首个线程2节点。

    1. 我们知道,AQS同步队列中目前没有节点,则要首先New一个新的节点,然后会初始化一个NULL空节点。这点一定要理解。
    image-20210913214614548.png image-20210913214651339.png
    1. 队列中目前已有节点,则尾部插入。

    2. 中部插入(aqs不存在)

    1.2.3阻塞(park)

    image-20210913214840806.png

    1.2.4释放锁

    1. 修改锁标志位state
    2. 从同步器头结点head开始,unparkSuccessor(head) ,h.waitStatus等待闹钟的状态变化-1(需要唤醒后继节点)-->0(回归初始状态)
    3. 找到唤醒节点s,LockSupport.unpark(s.thread); // 唤醒线程T2,通过步骤2和步骤3我们知道要对等待闹钟waitStatus进行2次操作
    public final boolean release(int arg) {
            if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
    
    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;
            if (ws < 0) // 等待闹钟:-1-->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;
            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);
        }
    

    1.2.5唤醒(T2线程)

    //1.parkAndCheckInterrupt
    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
    // 2.selfInterrupt(); os给唤醒的线程中断信号
    // 3.T2线程继续执行自己的业务逻辑
    
    image-20210913214923492.png

    1.2.6出队(过号)

       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) // 这里,failed=true,why todo
                    cancelAcquire(node);
            }
        }
    

    相关文章

      网友评论

          本文标题:2021-08-11_AQS6个核心操作图解总结

          本文链接:https://www.haomeiwen.com/subject/fgycbltx.html