美文网首页
非公平锁的上锁过程

非公平锁的上锁过程

作者: kele2018 | 来源:发表于2020-03-19 14:08 被阅读0次

    1、lock

    final void lock() {
                //一进来就可以尝试获取锁  不用管自己前面是否已经有人在排队
                if (compareAndSetState(0, 1))
                    //拿到锁且可以用   就在锁上标记一下  哪个线程在用这把锁
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    acquire(1);
      }
    

    2、acquire

    public final void acquire(int arg) {
            /**
             * tryAcquire(arg)这个方法是留给子类覆盖的   给我们一个自定义获取锁逻辑的机会
             * addWaiter(Node.EXCLUSIVE)这个方法会把当前线程封装成一个Node对象,然后添加到链表(双向)中
             */
            if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
                selfInterrupt();
            }
        }
    

    2.1、tryAcquire

    
    protected final boolean tryAcquire(int acquires) {
           return nonfairTryAcquire(acquires);
     }
    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()) {  //ReentranLock为可重入锁
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
    
    

    2.2、addWaiter

    private Node addWaiter(Node mode) {
            //把当前没有获取锁的线程封装成一个node对象
            Node node = new Node(Thread.currentThread(), mode);
            //拿到尾部节点
            Node pred = tail;
            if (pred != null) {
                //当前节点的prev指向尾部节点
                node.prev = pred;
                //设置尾部节点为当前节点
                if (compareAndSetTail(pred, node)) {
                    //设置原先尾部节点的next为当前节点
                    pred.next = node;
                    return node;
                }
            }
            enq(node);
            return node;
        }
    
    

    2.2.1、 enq

    private Node enq(final Node node) {
            for (;;) {
                Node t = tail;
                if (t == null) {
                    /**
                     * 初始化head节点和tail节点,让它们都指向一个空节点
                     * 这就相当于把第一个位置空出来,以后哪个线程坐在这个位置上哪个线程就工作,而有资格获取锁的线程永远是排在第一个位置后的线程
                     */
                    if (compareAndSetHead(new Node())){
                        tail = head;
                    }
                } else {
                    /**
                     * 这里就是快速入链表的过程,完成三件事
                     * 1、尾部节点指向当前节点
                     * 2、原先的尾部节点的next节点指向当前节点
                     * 3、当前节点的prev节点指向原先的尾部节点
                     */
                    node.prev = t;
                    if (compareAndSetTail(t, node)) {
                        t.next = node;
                        return t;
                    }
                }
            }
        }
    

    2.3、acquireQueued

    final boolean acquireQueued(final Node node, int arg) {
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    //返回node的prev
                    final Node p = node.predecessor();
                    //只有排在head节点之后的线程才能尝试去获取锁
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return interrupted;
                    }
                    /**
                     * shouldParkAfterFailedAcquire(p, node) 这个方法决定了当前线程是否要park
                     */
                    if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()){
                        interrupted = true;
                    }
    
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    

    2.3.1 shouldParkAfterFailedAcquire

    
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
            int ws = pred.waitStatus;
            //ws=-1
            if (ws == Node.SIGNAL)
                //当一个节点的上一个节点的waitStatus等于-1的时候,当前节点需要阻塞
                return true;
            if (ws > 0) {
    
                do {
                    /**
                     * 把当前节点的上一个节点从链表中拿掉
                     * 说明当一个节点的waitStatus大于0的时候,说明这个节点不想再等待了,所以就应该把它从链表中拿掉
                     */
                    node.prev = pred = pred.prev;
                } while (pred.waitStatus > 0);
                pred.next = node;
            } else {
    
                /**
                 * 更新上一个节点的waitStatus为-1
                 *
                 * 说明当上一个节点的waitStatus除了上面两种情况    都要更新waitStatus为-1
                 *
                 */
                compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
            }
            return false;
        }
    

    相关文章

      网友评论

          本文标题:非公平锁的上锁过程

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