ReentrantLock+Condition源码解析

ReentrantLock通过Sync对象实现锁功能, 抽象Sync对象继承了aqs,有两个子类NonfairSync和FairSync分别 对应非公平锁和公平锁,默认使用非公平锁。

非公平锁NonfairSync

lock

final void lock() {
    //尝试将state通过cas设置为1,设置成功表示抢占锁成功
    if (compareAndSetState(0, 1))
        //设置独占锁的线程为当前线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
//1.tryAcquire,如果成功,则意味着该线程获得了锁,不需要再做处理,否则继续
//2.addWaiter将线程封装为了Node节点,并承担了初始化线程Node节点链表的任务,
//3.acquireQueued
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
//尝试通过非公平抢占和可能存在的锁重入,获得锁,
//获得锁,则返回true,并设置当前线程为独占线程ExclusiveOwnerThread;
//否则返回false
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    //判断当前state==0,说明此时处于未被锁定状态
    if (c == 0) {
        //因为是非公平锁,所以再次尝试cas尝试抢占锁
        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;
}

private Node addWaiter(Node mode) {
    //封装到node节点对象
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    //如果tail不为空,则直接尝试进行一次tail的cas操作,
    //成功,则直接将新增的节点,加入到了尾节点作为tail,并返回node
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //如果是刚初始化的,或者尝试了一次cas失败的,走enq
    enq(node);
    return node;
}

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        //针对初始化的。设置头节点,也可能多个线程同时操作,因而使用cas,
        //失败的说明有其他线程完成了该操作,则自旋重试
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                //初始时,头尾节点指向空node
                tail = head;
        } else {
            node.prev = t;
            //cas尝试设置尾节点,成功则将尾节点的next设置为node
            //否则,意味着当前操作还有别的线程也在处理,自旋重试
            if (compareAndSetTail(t, node)) {
                t.next = node;
                //返回新增节点的父节点
                return t;
            }
        }
    }
}

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //获取node的前一节点
            final Node p = node.predecessor();
            //如果恰好是head节点,则尝试获取锁
            //如果是获取锁成功(tryAcquire已经设置了独占线程),
            //将原本的头节点有关信息清理,并设置当前节点为头节点
            //setHead除了设置头节点,还清空了node中持有的线程和prev对象
            //node中持有的线程对象因为该线程已经设置到了ExclusiveOwnerThread,
            //所以也没必要再缓存一份, 
            //因为是双向链表,所以头节点的清理,是清理该节点的next和子节点的prev
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //走到这一步就是判断是否暂停该线程了
            //如果链表是刚创建的,此时父节点NOde 是空的,
            //走shouldParkAfterFailedAcquire方法的话,waitStatus=0,
            //因而只是将父节点设为SIGNAL
            //但是,还未跳出循环,还要自旋,下一次再走到这,waitStatus=SIGNAL就需要暂停线程了
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
//节点状态CANCELLED=1,SIGNAL=-1,CONDITION=-2,PROPAGATE=-3
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    //如果父节点是SIGNAL状态,则返回true
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    //从上面的节点状态,可以看到ws即waitStatus>0,即为取消状态,需要清理
    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 {
        //将父节点设为SIGNAL状态(此时方法返回false)
        /*
         * 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.
         */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}
//该函数有意思的点是先调用了park函数,又复位 Thread.interrupted()返回了是否中断标志
//因为如果线程先通过park函数,暂停,其他线程又调用了该线程的Interrupt方法,
//Interrupt在hotspot源码中,会调用unpark函数,即打断了park,
//此时,在acquireQueued函数中会继续自旋,但是 因为是Interrupt状态,
//并且park在hotspot源码中,会判断,如果是设置了打断状态,就直接返回,不起作用
//因而,需要使用Thread.interrupted()复位,在之后的自旋中再次park暂停
private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

unlock


```java
public final boolean release(int arg) {
    //如果不在占有锁
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

//根据重入次数state-释放次数,
//如果为0,意味着当前线程不再需要占有锁,设置ExclusiveOwnerThread=null,返回true
//否则,只是扣减释放次数,返回false
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;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

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;
    //当前节点waitStatus为负数,在当前ReentrantLock中,也就是SIGNAL,
    //表示后续有被阻塞的线程节点
       if (ws < 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.
     */
    Node s = node.next;
    //如果后续节点为取消状态CANCELLED=1,则找到第一个非CANCELLED状态节点
    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);
}

condition

ReentrantLock.newCondition()是通过Sync对象创建,而Sync的newCondition方法只有种实现(不区分公平非公平),因而只需要看aqs下的ConditionObject

await

 public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //将线程封装到node节点,并添加到链表尾部
    Node node = addConditionWaiter();
    //释放锁,或者说从reentrantlock的等待队列中将本线程全部移除,不再占有锁
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    //如果不在同步队列中,则park暂停
    while (!isOnSyncQueue(node)) {
        //通过condition.await等待的就停在这
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

private Node addConditionWaiter() {
    Node t = lastWaiter;
    // If lastWaiter is cancelled, clean out.
    if (t != null && t.waitStatus != Node.CONDITION) {
        //清理被取消节点
        unlinkCancelledWaiters();
        //如果最终节点上被取消状态,那么最终节点肯定会变(向前移位或者变为null)
        t = lastWaiter;
    }
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    //初始化链表或者直接加入到最终节点的子节点上
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    //新增节点肯定是尾节点,所以直接赋值
    lastWaiter = node;
    return node;
}

//从头检查清理被取消节点
private void unlinkCancelledWaiters() {
    //从头节点开始遍历
    Node t = firstWaiter;
    Node trail = null;
    while (t != null) {
        //先拿到下一个节点,作准备
        Node next = t.nextWaiter;
        //判断当前节点是否在等待,或者说是被取消
        if (t.waitStatus != Node.CONDITION) {
            //如果是被取消状态,则需要清理
            //首先将该节点的next设为空
            t.nextWaiter = null;
            //首先,trail是放的,已遍历的有效节点的尾节点,所以如果trail==null说明还没遍历到有效节点
            //暂时用firstWaiter放置next节点,(如果下一次遍历后trail还是null,那就再设置一次)
            if (trail == null)
                firstWaiter = next;
            else
                //这个地方就是用trail暂时性
                的连接到next节点,因为和上面一样,如果下一个节点next还是要被取消的
                //那就重新将trail的next设为next.next,只有找到了一个有效的next,trail才会向后移
                trail.nextWaiter = next;
            //如果子节点为空,那毋庸置疑,最终的有效节点的尾节点,就是trail,  
            //即遍历到最终节点的时候,已知这个节点是要被删除的,那么lastWaiter节点肯定就变成了之前遍历过的某一个有效接待你,即trauil
            //而如果最终节点是有效节点,那lastWaiter就不需要改变,因而只需要在这种最终节点为删除节点的情况下处理lastWaiter即可
            if (next == null)
                lastWaiter = trail;
        }
        else
            //说明当前节点t是有效节点,可以置为trail
            trail = t;
        t = next;
    }
}

final int fullyRelease(Node node) {
    boolean failed = true;
    try {
        //获取重入次数
        int savedState = getState();
        //释放锁
        if (release(savedState)) {
            failed = false;
            return savedState;
        } else {
            throw new IllegalMonitorStateException();
        }
    } finally {
        if (failed)
            node.waitStatus = Node.CANCELLED;
    }
}
//判断当前节点是否存在于同步队列中
final boolean isOnSyncQueue(Node node) {
    //如果节点是condition状态或者prev==null
    //因为在condition中构建的链表是通过nextwaiter实现的连接,没有使用prev
    //而在同步队列中,会有一个空Node作为头节点,所以肯定prev不是null,所以可以根据这个判断是否在同步队列上
    if (node.waitStatus == Node.CONDITION || node.prev == null)
        return false;
     //与prev类似,next也只在同步队列中用了
    if (node.next != null) // If has successor, it must be on queue
        return true;
    //从同步队列中的尾节点看能不能找到该节点,找到了,就是在同步队列中,返回true
    return findNodeFromTail(node);
}

private boolean findNodeFromTail(Node node) {
    //获得同步队列的尾节点
    Node t = tail;
    for (;;) {
        //找到了返回true
        if (t == node)
            return true;
        //没找到返回false    
        if (t == null)
            return false;
        //向前移位    
        t = t.prev;
    }
}

signal

public final void signal() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}
//不断向下遍历,直到有一个transferForSignal返回true或者到最终节点
private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
     //从注释可知,如果通过 cas CONDITION到0 失败,则意味着该节点有问题或者是已经被取消
     //返回false即node状态迁移失败
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;
    //aqs的enq方法,将该节点加入到同步队列中,返回新增节点node在同步队列的父节点    
    Node p = enq(node);
    int ws = p.waitStatus;

    //ws > 0即 父节点被取消的节点,
    //或者cas父节点状态为signal的失败的情况下(有可能在并发情况下,该线程在获取ws是还是正常的,cas时却变为了取消状态)unpark,尝试获取锁
    //个人理解:
    
    //因为本线程执行完signal后,可能很快就unlock,unlock可能就会释放锁、唤醒某线程争抢锁的操作,
//此时可以尝试unpark node线程,让该node线程尝试获取锁。而非等待同步队列中的唤醒操作。
//因为同步队列中的唤醒操作可能会出现从尾节点向前找到最前面的一个有效节点并唤醒,这种遍历操作,而此时肯定是有一个线程获得锁,不如让当前这个有效的节点尝试获取下,节省了部分时间。
    
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true

以上为个人对于源码的理解和注释,如有错误或疑问,欢迎一起讨论,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值