zoukankan      html  css  js  c++  java
  • ReentrantLock线程未获取到锁进入等待队列原理

    公平锁  

    非公平锁 都会调用acquire方法

        public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }

    1 使用tryacquire获取锁 2 未获取到锁,则将当前线程添加到等到队列

    acquireQueued(addWaiter(Node.EXCLUSIVE), arg))原理剖析
    1. 线程A获取到锁,但是未释放
    2. 线程B尝试获取锁,但是锁未被释放,因此进入等待队列
    3. 线程C尝试获取锁,但是锁未被释放,因此进入等待队列
    
    

     AbstractQueuedSynchronizer

        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);
            }
        }

     当前线程的前驱不是head节点(空节点,不存储线程相关信息),且获取锁失败(tryAcquire),则判断是否需要阻塞当前线程 shouldParkAfterFailedAcquire
    
    
        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;
        }
    
    

     判断当前线程是否需要被阻塞(加入等待队列)流程图 shouldParkAfterFailedAcquire

    
    
  • 相关阅读:
    [贪心] Jzoj P4249 游戏
    [数学][快速幂] Jzoj P4248 n染色
    [dfs] Jzoj P4252 QYQ的图
    [折半搜索][has] Jzoj P4250 路径
    [计数dp][数学] Jzoj P4254 集体照
    [Tarjan][并查集][dp] Jzoj P4253 QYQ在艾泽拉斯
    [支配树][lca][倍增][线段树][拓扑] Jzoj P4240 游行
    [贪心] Jzoj P4244 yi
    [数位dp] Jzoj P4239 光棍
    [扫描线][差分约束] Jzoj P4238 纪念碑
  • 原文地址:https://www.cnblogs.com/lt123/p/12837894.html
Copyright © 2011-2022 走看看