阻塞队列
阻塞队列是一个支持两个附加操作的队列,这两个操作支持阻塞的插入和移除方法。
- 支持阻塞的插入方法:当队列满时,队列会阻塞插入元素的线程,直到队列不满。
- 支持阻塞的移除方法:在队列为空时,获取元素的线程会等待队列变为非空。
7个阻塞队列
ArrayBlockingQueue
一个用数组实现的有界阻塞队列,按照先进先出的原则对元素进行排序
默认情况下不保证线程公平的访问队列,所谓公平访问队列是指阻塞的线程,可以按照阻塞的先后顺序访问队列,即先阻塞先访问。非公平是对先等待的线程是非公平的,当队列可用时,阻塞的线程都可以争夺访问队列的资格,有可能先阻塞的队列最后才访问。
LinkedBlockingQueue
一个用链表实现的有界阻塞队列,此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出对元素进行排序。
ProiorityBlockingQueue
一个支持优先级的无界阻塞队列。默认情况下元素采取自然顺序升序排列。也可以用compareTo()方法指定排序规则
DelayQueue
一个支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口在创建元素时可以指定多久才能从队列中获取当前元素。
应用场景:
缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行。比如TimeQueue
SynchronousQueue
一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。
它支持公平访问队列。默认情况下线程采用非公平性策略访问队列。
LinkedTransferQueue
一个由链表结构组成的无界阻塞TransferQueue队列。多了tryTransfer和transfer方法。
transfer: 可以把生产者传入的元素理科transfer给消费者。如果没有消费者在等待接受元素,transfer方法会将元素存放在队列的tail节点,并等到该元素被消费者消费了才返回。
trytransfer: 试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回false。还可以带有时间参数的限制。
LinkedBlockingDeque
一个由链表结构组成的双向阻塞队列。可以从队列两端进行插入和移除元素。
实现原理
使用通知模式实现。当生产者往满的队列里添加元素时会阻塞生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。
ArrayBlockingQueue使用Condition来实现
private final Condition notFull;
private final Condition notEmpty;
public ArraylockingQueue(int capacity,boolean fair){
notEmpty=lock.newCondition();
notFull=lock.newCondition();
}
public void put(E e)throws InterupptedException{
checkNotNull(e);
final ReetrantLock lock=this.lock;
lock.lockInterruptibly();
try{
while(count==items.length)
notFull.await();
insert(e);
}finally{
lock.unlcok();
}
}
public E take() throws InterruptedException{
final ReetrantLock lock=this.lock;
lock.lockTnterruotibly();
try{
while(count==0)
notEmpty.await();
return extract();
}finally{
lock.unlock();
}
}
private void insert(E x){
items[putIndex]=x;
putIndex=inc(putIndex);
++count;
notEmpty.signal();
}