条件队列的典型的实现就是:阻塞队列。有元素就通知线程处理,无元素就阻塞线程等待。看条件队列,先看其 等待/通知 的实现。
1、ConditionObject的结构:
2、ConditionObject是interface Condition的实现类。其主要的接口是await和signal:
await():不限时等待。
await(long time, TimeUnit unit):限时等待,可以指定时间单位。
awaitNanos(long nanosTimeout):限时等待,时间单位为纳秒。
awaitUninterruptibly():不可中断的限时等待。
awaitUntil(Date deadline):限时等待,指定超时时间为将来的某个时间点。
signal():通知等待队列里节点(firstWaiter指向的第一个Node)。
signalAll():通知等待队列里所有的节点。
先看等待 await方法(注意下里面的这个checkInterruptWhileWaiting方法)
checkInterruptWhileWaiting 方法里调用了 transferAfterCancelledWait。到这里证明是被signal唤醒了。如果当前节点还没有被加入到同步队列,则让出cpu时间片继续查询是否已经加入。
唤醒 signal方法
Condition.await/Condition.signal 与Object.wait/Object.notify区别:
前者是AQS和lock在jdk实现,后者是 synchronized JVM实现
以上就是条件队列的通知与唤醒的实现。现在看下阻塞队列是如何依赖此实现的。
阻塞队列的实现主要是基于 Condition队列的条件中转 以及 ReentrantLock来实现的(一个notEmpty队列记录的是取元素,notFull记录的是put元素)。
流程(ArrayBlockingQueue为列,以下简称 abq):
1、初始化大小为1的阻塞队列abq.
2、线程p1放入一个元素进abq。
3、放入后通知notEmpty条件队列里面阻塞的现线程来取数据,如果notEmpty中此时没有等待排队的线程,那此时abq长度为1.
4、线程p2又来放一个元素进abq。
5、此时abq在放入前已经满了,而此时线程2不能再放入了,它将进入一个notFull的队列等待。
6、此时一个一个线程 t1来取,取完之后abq的长度为0,小于最大长度1,则取完后通知p2继续往里面放。
7、p2被唤醒signal之后,从原来的notFull队列转移到同步队列当中。转移到同步队列中的方法上面已经讲了在 signal方法中
8、同样的如果元素都被取完还有线程来取,则加入到notEmpty队列中等待有线程put后被其signal。
注:这里一定要区分条件队列和同步队列的关系,以及条件队列向同步队列的转移。同步队列永远不回去唤醒条件队里的线程。
除此之外的 DelayQueue等队列,都是以此原来的一些功能拓展。
下面一次更新讲的线程池,就是根据阻塞队列来进行的。。