• AQS源码的一点思考


    /**
         * Acquires in exclusive uninterruptible mode for thread already in
         * queue. Used by condition wait methods as well as acquire.
         *
         * @param node the node
         * @param arg the acquire argument
         * @return {@code true} if interrupted while waiting
         */
        final boolean acquireQueued(final Node node, int arg) {
            boolean failed = true;
            try {
                boolean interrupted = false;
                // 这里是一个自旋操作,用来进行获取锁或者进入阻塞的动作
                for (;;) {
                    final Node p = node.predecessor();
                    // 如果前驱节点为头节点(head,其实是一个虚节点,不关联任何线程),
                    // 并且尝试加锁(tryAcquire)成功的话,讲当前节点设置为头节点(head)
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return interrupted;
                    }
                    // 如果当前节点的前驱节点不是头节点,或者是头节点但是没有抢到锁(被非公平锁抢占了)
                    // 就会通过shouldParkAfterFailedAcquire判断当前节点是否需要将自己挂起,进入阻塞状态
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
    /**
         * Checks and updates status for a node that failed to acquire.
         * Returns true if thread should block. This is the main signal
         * control in all acquire loops.  Requires that pred == node.prev.
         *
         * @param pred node's predecessor holding status
         * @param node the node
         * @return {@code true} if thread should block
         */
        private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
            int ws = pred.waitStatus;
            // 如果当前节点的前驱节点的waitStatus为Node.SIGNAL的话,
            // 就意味着当前节点需要进入阻塞状态,将自己挂起
            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.
                 */
                // 如果当前节点的前驱节点的waitStatus>0的话,意味着前驱节点的waitStatus=CANCELLED,
                // 那么就要从前往后遍历,将CALCELLED的前驱节点都从链表中摘除
                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.
                 */
                // 如果前驱节点的waitStatus不是CANCELLED(1),也不是SIGNAL(-1),
                // 那就将当前节点的前驱节点的waitStatus设置为SIGNAL(意思就是当前节点需要进入阻塞状态,
                // 当然这里只是先将当前节点的前驱节点的waitStatus设置为SIGNAL,
                // 下一轮自旋才能将当前节点设置为阻塞状态)
                compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
            }
            return false;
        }
    
  • 相关阅读:
    无线Mesh网络技术基础与应用
    BLE低功耗蓝牙关键技术解析与应用
    Android Studio NDK开发入门
    Android 注解的使用与注意事项
    图形图像处理库大全
    vs2010下C++调用lib或dll文件
    网线连接电脑共享文件传递
    分配和释放 BSTR 的内存
    #include <objsafe.h>//OCX控件在IE8浏览器下不能使用问题
    彻底搞定char/wchar_t/unicode
  • 原文地址:https://www.cnblogs.com/rocker-pg/p/12510949.html
Copyright © 2020-2023  润新知