ReentrantLock & AQS源码整理(1)--非公平锁

文章仅用来自己整理、记录,不成体系,无法阅读!

ReentrantLock类图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ReentrantLock 主要就是通过实现 AQS 达到锁的效果,可以实现和synchronized一样的效果,并且具有扩展功能。如超时,支持公平锁。

构造函数
/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
     // 可以通过参数控制开启公平锁,默认非公平锁
     // 公平锁会导致吞吐下降
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

获取锁
/**
     * Acquires the lock.
     *
     * <p>Acquires the lock if it is not held by another thread and returns
     * immediately, setting the lock hold count to one.
     * 如果当前锁未被其他线程获取,则当前线程获取锁立即返回,设置计数器为1
     *
     * <p>If the current thread already holds the lock then the hold
     * count is incremented by one and the method returns immediately.
     * 重入:如果当前线程已经获取到该锁,则计数器加1立即返回
     *
     * <p>If the lock is held by another thread then the
     * current thread becomes disabled for thread scheduling
     * purposes and lies dormant until the lock has been acquired,
     * at which time the lock hold count is set to one.
     * 如果当前锁被其他线程获取,则当前线程将被阻塞,直到获取到锁,设置计数器为1
     */
    public void lock() {
    	// 内部调用AQS设置状态为1
        sync.acquire(1);
    }
AQS acquire()

/**
     * 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();
    }
    
ReentrantLock.Sync tryAcquire()

// 非公平同步器调用nonfairTryAcquire
protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

/**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        @ReservedStackAccess
        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()) {
                int nextc = c + acquires;
                // 溢出
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
AQS addWaiter
/**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
     // 将当前 node 插入到队尾
    private Node addWaiter(Node mode) {
    
        Node node = new Node(mode);

        for (;;) {
            // 找到尾节点
            Node oldTail = tail;
            if (oldTail != null) {
                // 设置关联 node.prev = oldTail
                node.setPrevRelaxed(oldTail);
                // cas 修改尾节点
                if (compareAndSetTail(oldTail, node)) {
                    oldTail.next = node;
                    return node;
                }
            } else {
                // 初始化头尾节点
                initializeSyncQueue();
            }
        }
    }
	/**
     * Initializes head and tail fields on first contention.
     */
    private final void initializeSyncQueue() {
        Node h;
        // 头和尾设置同一个节点
        if (HEAD.compareAndSet(this, null, (h = new Node())))
            // TODO 这里为什么不使用 CAS
            // 调用该方法一定是 tail == null
            // 假如第一个线程设置头成功后没有设置尾节点
            // 此时第二个线程仍然走到该方法,并且 CAS 头节点失败
            // 因此,该逻辑一定是线程安全的
            tail = h;
    }
AQS 入队操作
/*
     * Various flavors of acquire, varying in exclusive/shared and
     * control modes.  Each is mostly the same, but annoyingly
     * different.  Only a little bit of factoring is possible due to
     * interactions of exception mechanics (including ensuring that we
     * cancel if tryAcquire throws exception) and other control, at
     * least not without hurting performance too much.
     */

    /**
     * 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 interrupted = false;
        try {
            for (;;) {
                // 获取前一个节点
                final Node p = node.predecessor();
                // 如果是第一个节点 再次尝试获取锁
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    return interrupted;
                }
                // 是否需要挂起
                if (shouldParkAfterFailedAcquire(p, node))
                    // 挂起并清除中断状态
                    interrupted |= parkAndCheckInterrupt();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            if (interrupted)
                selfInterrupt();
            throw t;
        }
    }

	/**
     * 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;
        // 前节点状态是 SIGNAL,park
        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 {
            // ws <= 0
            /*
             * 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.
             */
            // 前节点设置为通知状态
            // 死循环调用,第一遍设置为通知状态,下次进入会挂起
            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
        }
        return false;
    }

加锁流程
如果当前锁未被其他线程获取,尝试获取锁
如果获取锁的线程是当前线程,锁状态字段值加1
如果获取锁不成功,入等待队列,并且不间断尝试,或者执行挂起操作

tryLock直接调用nonfairTryAcquire,不执行入队列操作,无论是否成功获取锁,直接返回。
所以,公平锁无法执行tryLock

有时间限制的获取锁流程和lock流程基本一致
区别:

  • 获取锁不成功需要判断是否达到超时时间
  • 挂起操作需要设置超时时间
tryLock(long timeout, TimeUnit unit)
tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout)

/**
     * Acquires in exclusive timed mode.
     *
     * @param arg the acquire argument
     * @param nanosTimeout max wait time
     * @return {@code true} if acquired
     */
    private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                // 超时返回
                if (nanosTimeout <= 0L) {
                    cancelAcquire(node);
                    return false;
                }
                // 是否挂起 1.前置节点是通知状态 2.等待时间小于自旋时间
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
    }
解锁操作

调用 AQS release方法

/**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(int arg) {
        // 只有完全释放锁的时候才返回 true
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
            	// 唤醒后继节点
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

/**
     * Wakes up node's successor, if one exists.
     *
     * @param node the node
     */
    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            // 清除掉取消的节点
            s = null;
            // TODO 为什么从尾节点开始遍历?
            // 盲猜:
            // 正常情况,找到后继节点唤醒
            // 如果后继节点是取消状态
            // 如果从前向后查找,可能会出现其他线程将当前节点 next 断开的情况,无法找到后继需要唤醒的节点
            // 如果从后向前查找,prev 指向不会断开,可以保证需要唤醒的节点正常唤醒
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

取消操作
/**
     * Cancels an ongoing attempt to acquire.
     *
     * @param node the node
     */
    private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        // Skip cancelled predecessors
        // 跳过前边的已经取消的节点
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        // predNext is the apparent node to unsplice. CASes below will
        // fail if not, in which case, we lost race vs another cancel
        // or signal, so no further action is necessary, although with
        // a possibility that a cancelled node may transiently remain
        // reachable.
        Node predNext = pred.next;

        // Can use unconditional write instead of CAS here.
        // After this atomic step, other Nodes can skip past us.
        // Before, we are free of interference from other threads.
        node.waitStatus = Node.CANCELLED;

        // If we are the tail, remove ourselves.
        // 如果 node 是尾节点,移除 node,替换 tail 为 pred
        // pred next 设置为 null,后边的节点都是被取消的节点
        if (node == tail && compareAndSetTail(node, pred)) {
            pred.compareAndSetNext(predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            // pred 不是 head
            // pred 是通知状态或者 未被取消且设置通知状态并且线程不为空
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
                pred.thread != null) {
                // 设置 pred.next = node.next
                Node next = node.next;
                // TODO 如果 next.waitStatus > 0?
                //
                if (next != null && next.waitStatus <= 0)
                    pred.compareAndSetNext(predNext, next);
            } else {
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值