ReentrantLock 源码解读

360 阅读2分钟

实现的接口 lock 定义了一些方法

图片.png

public ReentrantLock() {
    // 默认非公平锁  传true 是公平锁  默认是非公平锁 
    // 
    sync = new NonfairSync();
}

lock 获取锁逻辑

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    /**
     * Performs lock.  Try immediate barge, backing up to normal
     * acquire on failure.
     */
    final void lock() {
         //  CAS 比较交换 把state 改成1就是获取了锁成功  独占锁
        if (compareAndSetState(0, 1))
            // 获取锁成功后 咋办 标识 获取锁的线程是那个 设置属性
            setExclusiveOwnerThread(Thread.currentThread());
        else
            // 获取锁失败后咋办
            acquire(1);
    }

    // 实现类中的方法 tryAcquire
    protected final boolean tryAcquire(int acquires) {
        // 获取锁失败后 重新获取锁
        return nonfairTryAcquire(acquires);
    }
}

acquire 获取锁失败后咋办

public final void acquire(int arg) 
{
    //  1、获取锁成功   
    // 2  获取锁失败 acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 执行逻辑
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

nonfairTryAcquire 重新获取锁

final boolean nonfairTryAcquire(int acquires) 
{
    //  acquires=1
    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;
}

addWaiter 没有获取锁的线程添加到等待队列中

private Node addWaiter(Node mode) 
{
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    if (pred != null) 
    {
        // 如果队列中有元素 把当前线程数据封装成Node 数据结构 然后添加到队列末尾
        // 当前元素的上一个元素 =添加前的最后一个元素
        node.prev = pred;
        // cas 把要添加的元素设置成队列的末尾元素
        if (compareAndSetTail(pred, node)) 
        {
            // 设置成功后  添加前的最后一个元素的下一个元素的指针指向当前要添加的元素
            pred.next = node;、
            // 返回添加成功的元素
            return node;
        }
    }
    // 队列中没有元素
    enq(node);
    return node;
}

enq 当队列中没有元素的时候会执行这个方法 初始化队列 并且建立好链表关系

private Node enq(final Node node) 
{
    for (;;) 
    {
        Node t = tail;
        if (t == null) 
        { 
           // 队列中没有元素  CAS 构建队列 并且 头指针和尾指针 都指向 要添加的元素
            // CAS 成功的话 
            if (compareAndSetHead(new Node()))
                tail = head;
        } 
        else 
        {
            // CAS 构建队列 并且 头指针和尾指针 都指向 要添加的元素 成功后 再次执行这个for循环
            // 在高并发的情况下  可能在一开始都判断了这个队列是空的 然后进入到这里了
            // 其中某个线程优先执行 构建好了这个队列 
            // 所以当CPU时间片段切到这个线程的时候 
            // 开始操作链表 要添加的元素添加到队列中的末尾元素
            node.prev = t;
            if (compareAndSetTail(t, node)) 
            {
                t.next = node;
                // 返回添加成功的节点
                return t;
            }
        }
    }
}

acquireQueued 添加节点到队列中成功后要执行的逻辑

arg =1 node 添加到队列中的节点

final boolean acquireQueued(final Node node, int arg) 
{
    boolean failed = true;
    try 
    {
        boolean interrupted = false;
        for (;;) 
        {
            // step 1 获取添加到队列中的节点的上一个节点
             // node.predecessor() 获取元素的上一个节点
            // 其实就是判断传入的节点的上一个节点
             // 是不是队列中第一个元素 
            // 如果是尝试获取锁   tryAcquire 尝试获取锁
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) 
            {
                // 获取成功 又开始操作链表了  把 node 改成 首节点 也就是队列中的第一个元素
                
                setHead(node);
                p.next = null; // help GC
                // 也没有失败
                failed = false;
                // 没有中断 返回false
                return interrupted;
            }
            // 不满足条件  shouldParkAfterFailedAcquire 设置前驱节点waitStatus为-1
            // 成功后 阻塞当前线程 
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                // 中断成功
                interrupted = true;
        }
    } 
    finally 
    {
        // 如果失败 这段代码似乎是多余的
        if (failed)
            cancelAcquire(node);
    }
}

shouldParkAfterFailedAcquire

pred 当前节点的上一个节点, node 当前节点

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.
         */
         /*
             * 前驱节点已经设置了SIGNAL,闹钟已经设好,现在我可以安心睡觉(阻塞)了。
             * 如果前驱变成了head,并且head的代表线程exclusiveOwnerThread释放了锁,
             * 就会来根据这个SIGNAL来唤醒自己
             */
        return true;
    if (ws > 0) 
    {
    
        
             /*
             * 发现传入的前驱的状态大于0,即CANCELLED。说明前驱节点已经因为超时或响应了中断,
             * 而取消了自己。所以需要跨越掉这些CANCELLED节点,直到找到一个<=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.
         */
         
            /*
             * 进入这个分支,ws只能是0或PROPAGATE。
             * CAS设置ws为SIGNAL
             */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

lock.unlock() 释放锁

public void unlock() {
    sync.release(1);
}

release 释放锁

public final boolean release(int arg) 
{
     // 释放锁成功
    if (tryRelease(arg)) 
    {
        // 如果释放锁成功后 获取链表的首节点 判断首节点的waitStatus !=0 
        // 唤醒线程
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

tryRelease 释放锁逻辑 releases=1

protected final boolean tryRelease(int releases) 
{
    int c = getState() - releases;
    // 如果线程不一样报错 用于锁的线程和释放锁的线程必须是同一个线程
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) 
    {
        free = true;
        // 释放锁成功 拥有锁的线程重置为Null
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

unparkSuccessor 唤醒队列中的第一个元素重新去获取锁

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)
        // 
        // 将等待状态waitStatus设置为初始值0 
        compareAndSetWaitStatus(node, 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.
     */
     /**
     * 若后继结点为空,或状态为CANCEL(已失效),
     *则从后尾部往前遍历找到最前的一个处于正常阻塞状态的结点
     * 进行唤醒
     */
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        // 唤醒线程  也就是首节点线程
        LockSupport.unpark(s.thread);
}