java 中的阻塞队列
1、什么是阻塞队列:
- 支持阻塞的插入方法,意思是当队列满时,队列会阻塞插入元素的线程,知道队列不满。
- 支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。
插入和移除操作的4种处理方式:
方法/处理方式 | 抛出异常 | 返回特殊值 | 一直阻塞 | 超时退出 |
插入方法 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除方法 | remove() | poll() | take() | poll(time, unit) |
检查方法 | element() | peek() | 不可用 | 不可用 |
2、java里的阻塞队列:
- ArrayBlockingQueue:是一个用数组实现的有界阻塞队列。
- LinkedBlockingQueue:是一个永链表实现的有界阻塞队列。
- PriorityBlockingQueue:是一个支持优先级的无界阻塞队列。
- DealyQueue:是一个支持延时获取元素的无界阻塞队列。
- SynchronousQueue:是一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。
- LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列。
- LinkedTransferQueue:是一个由链表结构组成的无界阻塞TransferQueue队列。
重点:
DelayQueue非常有用,可以将DelayQueue运用在以下应用场景。
-
- 缓存系统的设计,可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能获取元素,标识缓存有效期到了。
- 定时任务调度,使用DelayQueue保存当天将会执行的任务和执行时间。一旦从DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用此实现的。
3、阻塞队列的实现原理:
使用通知模式实现。所谓通知模式,就是当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。查看ArrayBlockingQueue源码发现使用了Condition来实现,代码如下.
private final Condition notEmpty; private final Condition notFull; public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); } 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); } finally { lock.unlock(); } } public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return dequeue(); } finally { lock.unlock(); } } private void enqueue(E x) { // assert lock.getHoldCount() == 1; // assert items[putIndex] == null; final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length) putIndex = 0; count++; notEmpty.signal(); }