AQS理解之七——AQS中的条件队列

AQS中的条件队列

在AQS中还实现了一个类,ConditionObject,它实现了Condition接口,实现一个绑定在锁上的条件队列。

先看看他的uml图。

AQS理解之七——AQS中的条件队列_第1张图片

主要方法

它实现了Condition接口,主要实现的方法是await和signal以及它们的带时间参数方法。

条件队列的一般用法:

当满足某个条件时,通知正在等待这个条件的线程(signal)

当需要满足某个条件才能继续执行时,进行阻塞等待(await)

在AQS实现的ConditionObject中,使用了firstWaiter和lastWaiter的Node类来保存正在阻塞的线程节点。

在await时,是将当前线程插入链表,然后park线程,等待unpark。

signal时,将链表的第一个拿出来unpark。

signalAll则是拿出所有的进行unpark。

使用案例

在DelayQueue中使用到了Condition,如下:

在队列插入时,如果插入的节点就是peek节点(说明之前队列为空)则发出通知,顾名思义,发出的是一个available的通知,说明队列现在又可以用了。

在队列取出时,如果peek/first == null,说明队列现在为空,不能拿出数据,需要等待,则available条件队列开始等待,调用await,等待signal通知

private final Condition available = lock.newCondition();

//在队列插入时,如果插入的节点就是peek节点(说明之前队列为空)则发出通知,顾名思义,发出的是一个available的通知,说明队列现在又可以用了。
public boolean offer(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        q.offer(e);
        if (q.peek() == e) {
            leader = null;
            available.signal();
        }
        return true;
    } finally {
        lock.unlock();
    }
}
//在队列取出时,如果peek/first == null,说明队列现在为空,不能拿出数据,需要等待,则available条件队列开始等待,调用await,等待signal通知 
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        for (;;) {
            E first = q.peek();
            if (first == null)
                available.await();
            else {
                long delay = first.getDelay(NANOSECONDS);
                if (delay <= 0)
                    return q.poll();
                first = null; // don't retain ref while waiting
                if (leader != null)
                    available.await();
                else {
                    Thread thisThread = Thread.currentThread();
                    leader = thisThread;
                    try {
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        if (leader == null && q.peek() != null)
            available.signal();
        lock.unlock();
    }
}

你可能感兴趣的:(java基础知识,多线程,AQS)