简介

        condition可以通俗的理解为条件队列。当一个线程在调用了await方法以后,直到线程等待的某个条件为真的时候才会被唤醒。这种方式为线程提供了更加简单的等待/通知模式。Condition必须要配合锁一起使用,因为对共享状态变量的访问发生在多线程环境下。一个Condition的实例必须与一个Lock绑定,因此Condition一般都是作为Lock的内部实现。

condition下面看看这个接口提供的方法:

  1. await() :造成当前线程在接到信号或被中断之前一直处于等待状态。
  2. await(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
  3. awaitNanos(long nanosTimeout) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。返回值表示剩余时间,如果在nanosTimesout之前唤醒,那么返回值 = nanosTimeout - 消耗时间,如果返回值 <= 0 ,则可以认定它已经超时了。
  4. awaitUninterruptibly() :造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。
  5. awaitUntil(Date deadline) :造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。如果没有到指定时间就被通知,则返回true,否则表示到了指定时间,返回返回false。
  6. signal() :唤醒一个等待线程。该线程从等待方法返回前必须获得与Condition相关的锁。
  7. signal()All :唤醒所有等待线程。能够从等待方法返回的线程必须获得与Condition相关的锁。

这个接口是实现类是在AbstractQueuedLongSynchronizer和AbstractQueuedSynchronizer中的内部类ConditionObject。

下面我们来说说AbstractQueuedSynchronizer 这个版本的

创建这个对象:

ReentrantLock Lock =new ReentrantLock();
        Condition condition = Lock.newCondition();
//ReentrantLock类中的
    public Condition newCondition() {
        return sync.newCondition();
    }
//创建对象,方法在AbstractQueuedSynchronizer中
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

这个创建对象其实是调用了AbstractQueuedSynchronizer中的方法,生成了ConditionObject内部类。

方法分析

(1)await():实现考虑中断的等待,若thread中断,则抛出异常。

public final void await() throws InterruptedException {
            if (Thread.interrupted())//如果线程中断了抛出异常
                throw new InterruptedException();
            //对等待队列中节点进行判断若状态不为CONDITION,则删除
            //创建节点并添加到等待对队列尾部,
            Node node = addConditionWaiter();
            //释放当前锁释放成功并唤起该节点的后继节点
            long savedState = fullyRelease(node);
            int interruptMode = 0;
            //循环判断当前线程的Node是否在Sync队列中,如果不在,则park
            while (!isOnSyncQueue(node)) {
                //等待
                LockSupport.park(this);
                //当前线程在等待过程中是否发生中断,设置interruptMode的值来标志中断状态
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            //开始执行后,获取锁
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                //将清除CONDITION队列中所有非CONDITION状态的节点
                unlinkCancelledWaiters();
            //检测线程状态,中断
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }
private Node addConditionWaiter() {
            Node t = lastWaiter;
            //检查CONDITION队列中节点是否为cancelled状态
            if (t != null && t.waitStatus != Node.CONDITION) {
                //不是CONDITION状态删除CONDITION队列中不是CONDITION状态的节点
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            //新建一个CONDITION节点添加到CONDITION队列队尾
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }
final int fullyRelease(Node node) {
        boolean failed = true;
        try {
            //获取当前锁重入的次数
            int savedState = getState();
            //释放锁
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            //释放锁失败,则当前节点的状态变为cancelled
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }
final boolean isOnSyncQueue(Node node) {
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        if (node.next != null) // If has successor, it must be on queue
            return true;
        //检测是否在加锁对列中
        return findNodeFromTail(node);
    }
    private boolean findNodeFromTail(Node node) {
        Node t = tail;
        for (;;) {
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        }
    }
//检测当前线程的状态
private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

 final boolean transferAfterCancelledWait(Node node) {
	    //将该节点状态由CONDITION变成0,调用enq将该节点从CONDITION队列添加到CLH队列中
        //(但是在CONDITION队列中的nextWaiter连接并没有取消)
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            enq(node);
            return true;
        }
        //循环检测该node是否已经成功添加到加锁队列中
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
        }
 private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

总结:

await只能在当前线程获取了锁之后调用。因此CLH队列和CONDITION队列的情况为:当前处于CLH队列队首的节点调用await方法,新new一个node,添加到CONDITION队列队尾,然后在CLH队列队首释放当前线程占有的锁,唤醒后继节点。当前线程以新node的形式在CONDITION队列中park,等待被唤醒。

具体过程:

1.清理CONDITION队列中状态不为CONDITION的节点,将该线程封装成node,状态为CONDITION ,并添加到队尾

2.尝试释放当前占有的锁,释放成功唤醒该节点在加锁对列中的后继节点

3.循环调用isOnSyncQueue方法检测node是否再次到加锁队列中(其他线程调用signal或signalAll时,该线程可能从CONDITION队列中transfer到CLH队列中),如果没有,则park当前线程,等待唤醒,同时调用checkInterruptWhileWaiting检测当前线程在等待过程中是否发生中断,设置interruptMode的值来标志中断状态。如果检测到当前线程已经处于CLH队列中了,则跳出while循环。

4.调用acquireQueued阻塞方法来在加锁队列中获取锁。

5.若存在下个节点删除状态不为Condition的节点

6.检查interruptMode的状态,在最后调用reportInterruptAfterWait统一抛出异常或发生中断。

 

(2)signal():实现考虑中断的等待,若thread中断,则抛出异常。

public final void signal() {
            //判断锁是否是被当前线程独占不是则异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            //CONDITION队列不为null,则doSignal方法将唤醒CONDITION队列中所有的节点线程
            if (first != null)
                doSignal(first);
        }
//对CONDITION队列中从首部开始的第一个CONDITION状态的节点,执行transferForSignal操作,将node从CONDITION队列中转换到CLH队列中,同时修改CLH队列中原先尾节点的状态
	private void doSignal(Node first) {
            do {
		//当前循环将first节点从CONDITION队列transfer到CLH队列
		//从CONDITION队列中删除first节点,
        //调用transferForSignal将该节点添加到加锁队列中,成功则跳出循环
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }
	//两步操作,首先enq将该node添加到CLH队列中,其次若CLH队列原先尾节点为CANCELLED或者对原先尾节点CAS设置成SIGNAL失败,则唤醒node节点;否则该节点在CLH队列总前驱节点已经是signal状态了,唤醒工作交给前驱节点(节省了一次park和unpark操作)
	final boolean transferForSignal(Node node) {
        //如果CAS失败,则当前节点的状态为CANCELLED
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
		//enq将node添加到CLH队列队尾,返回node的prev节点p
        Node p = enq(node);
        int ws = p.waitStatus;
		//如果p是一个取消了的节点,或者对p进行CAS设置失败,则唤醒node节点,让node所在线程进入到acquireQueue方法中,重新进行相关操作
		//否则,由于该节点的前驱节点已经是signal状态了,不用在此处唤醒await中的线程,唤醒工作留给CLH队列中前驱节点
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }

总结:

对CONDITION队列中第一个CONDITION状态的节点(将该节点以及前面的CANCELLED状态的节点从CONDITION队列中出队),将该节点从CONDITION队列中添加到CLH队列末尾,同时需要设置该节点在CLH队列中前驱节点的状态(若前驱节点为cancelled状态或者给前驱节点执行CAS操作失败,则需要调用park操作在此处唤醒该线程,否则就是在CLH队列中设置前驱节点的signal状态成功,则不用在此处唤醒该线程,唤醒工作交给前驱节点,可以少进行一次park和unpark操作)