AbstractQueuedSynchronizer源码分析之独占锁实现

acquire()方法

调用tryAcquire()方法判断同步状态是否满足,如果不满足则将线程封装成节点,加入到同步队列。加入到队列后的线程会反复阻塞,每次被唤醒后都再次调用tryAcquire()方法判断同步状态是否满足,如果仍然不满足,继续阻塞等待,直至同步状态满足为止。由于该方法忽略中断,所以在被唤醒后不会判断线程是否被中断。相对地,acquireInterruptibly()方法在被唤醒后会判断线程是否被中断,所以他退出阻塞的条件有2个:1、线程被中断;2、同步状态满足。

addWaitor()方法:将将线程封装成节点,加入到同步队列。

acquireQueued()方法:调用LockSupport.park()方法进行阻塞,在每次被唤醒后都再次调用tryAcquire()方法判断同步状态是否满足。

/**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

acquireQueued()方法

调用LockSupport.park()方法进行阻塞,在每次被唤醒后都再次调用tryAcquire()方法判断同步状态是否满足。

    /**
     * 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();
//同步队列在初始化时,tail节点等于head节点,此后每加入一个新节点,则tail节点等于该新节点,详见addWaitor()方法
//如果它的前继节点等于头结点,并且同步状态满足,则将当前节点设置为头结点
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
//在当前节点获取锁失败时判断是否应该使线程阻塞等待
                if (shouldParkAfterFailedAcquire(p, node) &&
//如果应该阻塞,调用LockSupport.park()方法进行阻塞
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

shouldParkAfterFailedAcquire()方法

在当前节点调用tryAcquire()方法失败时,判断是否应该使线程阻塞等待。

线程应该阻塞等待的条件为:前继节点的waitStatus为SIGNAL。

针对前继节点的waitStatus,分为以下三种情形 :

  • 如果前继节点的waitStatus为SIGNAL,表示该节点请求在前继节点释放锁时通知它,所以应该阻塞等待;
  • 如果前继节点的waitStatus大于0,说明该节点的前继节点是cancelled状态,后续遍历找到状态不为cancelled状态的前继节点;
  • 如果前继节点的waitStatus等于0或者PROPAGATE,表示该节点请求在前继节点释放锁时通知它,但还不能调用park()方法进行阻塞,通过cas设置前继节点的waitStatus为SIGNAL;
    /**
     * 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;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
//如果前继节点的waitStatus为SIGNAL,表示该节点请求在前继节点释放锁时通知它,所以应该阻塞等待
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
//如果前继节点的waitStatus大于0,说明该节点的前继节点是cancelled状态,后续遍历找到状态不为cancelled状态的前继节点
            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等于0或者PROPAGATE,表示该节点请求在前继节点释放锁时通知它,但还不能调用park()方法进行阻塞,通过cas设置前继节点的waitStatus为SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值