一、Condition简介

Java对象的wait()、notify()以及notifyAll()方法,这些方法与synchronized关键字配合,可以实现等待/通知模式。Condition接口也提供了类似功能,与Lock配合可以实现等待/通知模式,但是两者还是有一些区别的。

对比项Object MoitorCondition
前置条件获取对象的锁调用Lock.lock()获取锁调用lock.newCondition()获取Condition
调用方式object.wait()condition.await()
等待队列个数1个多个
当前线程释放锁并进入等待状态支持支持
当前线程释放锁并进入等待状态,在等待状态中响应中断不支持支持
当前线程释放锁并进入超时等待状态支持支持
当前线程释放锁并进入等待状态到将来的某个时间不支持支持
唤醒等待队列中的一个线程支持支持
唤醒等待队列中的全部线程支持支持

二、Condition的实现原理

每个Condition对象都包含了一个FIFO队列,称为等待队列,该队列是实现等待/通知功能的关键。

2.1 等待队列

队列中的每个节点都包含了线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了condition.await()方法,那么该线程会释放锁、构造节点加入等待队列尾部同步队列和等待队列中节点类型都是同步器的静态内部类AbstractQueuedSynchronized.Node。等待队列的基本结构如图:
clipboard.png

2.2 等待

从队列的角度看await()方法,当调用await()方法时,相当于同步队列的首节点(当前获取锁的线程)移动到Condition的等待队列末端。
但是实际上同步队列的首节点并不会直接加入到等待队列,而是通过addConditionWaiter()方法把当前线程构造成一个新的节点并加入等待队列中。代码如下:

public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            // 构造一个新的Node节点,加入到等待队列末段
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                // 将当前线程挂起
                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);
        }

2.3 唤醒

调用Condition的signal()方法,将会唤醒在等待队列中等待时间最长的节点,也就是首节点,在唤醒节点之前,会将节点移到同步队列末端

public final void signal() {
        if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }

final boolean transferForSignal(Node node) {
       
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        // 将节点加到同步队列末端
        Node p = enq(node);
        int ws = p.waitStatus;
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }

kamier
1.5k 声望493 粉丝