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

    
    
  • 相关阅读:
    LeetCode 345. Reverse Vowels of a String 题解
    LeetCode 344. Reverse String 题解
    LeetCode 27. Remove Element 题解
    LeetCode 61. Rotate List 题解
    LeetCode 19.Remove Nth Node From End of List 题解
    Android耗电量
    Android 使用adb查看和修改电池信息
    Android AOP AspectJ 插桩
    Flask相关用法
    Monkey日志信息的11种Event percentage
  • 原文地址:https://www.cnblogs.com/lt123/p/12837894.html
Copyright © 2011-2022 走看看