Condition源码解析—依赖ReentrantLock

condition的几个api和object的几个方法非常相似,但是对于锁的控制力度更加强大了,比如控制粒度更细了,提供了更多的功能:

在一定时间内等待..等等。

那么就先来看一下平时的使用吧。

ReentrantLock lock = new ReentrantLock();
Condition condition= lock.newCondition();//构造方法,基本属于什么都没做,那么我就不讲这个了
condition.await();
condition.signal();

1.await()方法。

public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            //初始化链表的功能,设置当前线程为链尾
            Node node = addConditionWaiter();
            //释放锁
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            //将该线程阻塞:和后续的signal相呼应
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            //线程被唤醒了,但是需要重新放入aqs中
            //重新自旋+阻塞去尝试获取锁
            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 (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
}

2.signal()方法。

//总体来说,signal方法没有那么复杂
public final void signal() {
    //判断调用signal的是不是占有锁的线程
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //从这里可以看出,wait和signal是排队了的,是从第一个开始唤醒
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}
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 (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
        //放入aqs的队尾中:并返回之前队列的前一个节点
        Node p = enq(node);
        int ws = p.waitStatus;
        //如果前一节点本来就是唤醒状态或者前一节点正在被其他线程唤醒,那么也唤醒自己
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
}

3.signalAll()方法。见名知其意,大概是将全部唤醒,放入aqs队列中。

//感觉差不多的结构,如果有相似的,就不再详细讲解了。
public final void signalAll() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignalAll(first);
}
//哈哈,果然是这样,就是一个do while循环,一个个唤醒,因此也应该是存在排队的问题
private void doSignalAll(Node first) {
            lastWaiter = firstWaiter = null;
            do {
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            } while (first != null);
}

猜你喜欢

转载自blog.csdn.net/qq_40384690/article/details/82563811
今日推荐