需求分析:
1.向一个容器取数据的时候,如果没有需要的数据,需要如何处理?
2.往一个容器放入数据的时候,如果容器满了,需要如何处理?
对于第一种情况,业务场景不同的时候会做出不同的处理,比如:
A:向数据库查找记录的时候,如果没有记录,会返回空.
B:对于网页中的股票实时数据,Ajax采用轮循的方式才看数据是否存在.
C:在推送系统中,如果容器中没有可以推送的消息,将一直等待消息的到来.
对比这两业务场景的不同,A是需要的时候去获取数据,B,C是有数据就要马上处理.
对于第二情况,会出现几种不同的情况:
D:往硬盘写文件,文件满了,抛出异常.
E:立即返回false,放入数据失败.
F:等待容器不为空,不为空的时候放入数据.
阻塞队列:
JDK 7提供了7个阻塞队列,如下:
· ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
· LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
·PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
·DelayQueue:一个使用优先级队列实现的无界阻塞队列。
·SynchronousQueue:一个不存储元素的阻塞队列。
·LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
·LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
阻塞队列可以解决C,F两种情况.即:
取数据时,队列为空的时候,一直阻塞,直到队列放入数据,接到通知,解除阻塞,获取数据.
放数据时,队列满了,一直阻塞,直到队列有数据被取走,接到通知,解除阻塞,放入数据.
那么阻塞队列是如何做到的,先看ArrayBlockingQueue的源码:
取数据的时候:
ArrayBlockingQueue.task(){
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
{
while (count == 0)
notEmpty.await();
}//从逻辑上来说,只有放入数据的时候才会调用notFull.signal(),但是无法保证其他地方没有误调用,再检查一遍
return dequeue();//里面会调用notFull.signal();
} finally {
lock.unlock();
}
}
}
放数据的时候:
ArrayBlockingQueue.offer(){
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);//notEmpty.signal();
} finally {
lock.unlock();
}
}
}