BlockingQueue
BlockingQueue接口主要实现:
BlockingQueue中特有的put()和take()方法是Blocking的关键,这两个方法可以在队列为满,或者空的时候进行阻塞等到,当有新的任务被拿去执行或新的任务进入队列后,自动将线程唤醒
BlockingQueue的实现与使用
介绍添加元素的几种方法
- add():队列已满时,再添加会抛出异常——对应remove()
- offer():添加元素后,会返回一个boolean值,看是否添加成功。若队列已满,再添加不会抛异常,但是返回false,表示添加失败——对应poll()
- put():队列已满,再添加会阻塞——对应take()
通过以下字段实现put()和take()
// 1.字段
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
put()
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(); } }
take()
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return dequeue(); } finally { lock.unlock(); } }
几种常见的BlockingQueu:
-
- 直接提交队列:SynchronousQueue,没有容量,所以提交的任务不能保存,总是将任务交给空闲线程,如果没有空闲线程,就创建线程,一旦达到maximumPoolSize就执行拒绝策略
- 有界任务队列:ArrayBlockingQueue,当线程池的数量小于corePoolSize时,当有新的任务时,创建线程,达到corePoolSize后,则将任务存到ArrayBlockingQueue中,直到有界队列容量已满时,才可能会将线程数提升到corePoolSize之上。
- 无界队列:LinkedBlockingQueue,除非系统资源耗尽,否则不存在任务队列入队失败的情况,因此当线程数达到corePoolSize之后,就不会增加,有新的任务到来时,都会放到无界队列中。
- 优先任务队列:PriorityBlockingQueue是带有优先级的队列,特殊的无界队列,理论上来说不是先入先出的,是根据任务的优先级来确定执行顺序
- DelayQueue:执行定时任务,将任务按延迟时间长短放入队列中,延迟时间最短的最先被执行,存放在队列头部的是延迟期满后保存时间最长的任务
- LinkedTransferQueue,其实和SynchronousQueue类似,当生产者生产出产品后,当先去找是否有消费者,如果有消费者在等待资源,则直接调用transfer()方法将资源给消费者消费,而不会放入队列中。如果没有消费者等待,则当生产者调用transfer()方法时会阻塞,而调用其他的方法,如aput()则不会阻塞,会把资源放到队列中,因为put()方法只有在队列满的时候才会阻塞。适用于游戏服务器中,可以是并发时消息传递的效率更高