JAVA中阻塞队列BlockingQueue接口方法的多场景支持设计

JAVA中阻塞队列BlockingQueue接口方法的多场景支持设计

BlockingQueue是JDK中的常用接口类型,对于队列来讲,最常用的操作当属元素的入队与出队,而BlockQueue虽然叫阻塞队列,但是却通过对于入队和出队操作的分场景设计,实现了对多种场景需求的满足。需要阻塞的,需要抛出异常的,还是需要等待一个时间间隔不满足再失败的,都完美支持。

场景需求抛出异常的返回特定值的阻塞的超时的
插入元素(入队)boolean add(e)boolean offer(e)void put(e)boolean offer(e, time, unit)
移除元素(出队)boolean remove(Object o)E poll()E take()E poll(time, unit)
检查元素(只看看)E element()E peek()不适用不适用
我们来看一下各个方法的出处。
1、add与remove方法其实是继承自Collection接口。
2、E element()与E peek(),offer(e),E poll()四个方法,是继承自Queue接口。
3、void put(e)与E take()这两个纯粹的阻塞方法,是BlockingQueue接口特有的。
4、boolean offer(e, time, unit)与E poll(time, unit)这两个超时,其实也与阻塞有关,其实是可超时的阻塞。

从这几个角度理解这8+2个接口,就会非常清晰了,6个接口是爹生出它来的时候天生就带着的,其他4个接口才是真正的与阻塞队列特性相关的。这样,我们就能够在不同的场景需求下,精确的使用特定方法来进行处理。

举个例子,阻塞队列通常用于异步解耦,当接收并处理消息的线程在队列上轮询时,如果使用E poll()会出现空循环,那我们应该用E take()阻塞方法最佳,有消息就返回,没消息就呆着,但遇到需要批量处理时就会有问题。假定原计划10笔一批,结果第10笔阻塞住,怎么等也等不来了,可怎么好?

先检查下?然后再取?是一种办法。
这时候可以考虑poll(time, unit),等上几毫秒,如果等不来,且有已经组到半截的包(比如7笔)则结束当前包,形成一个批次;如果是空的,则进入下一此循环。这样既能够避免空转,也可以解决实时性问题。

BlockingQueue提供的这几个方法,组合使用,能够解决日常场景中的大部分需求,准确恰当的理解每个方法的使用场景,以及背后的原因和设计考虑也就变得非常有必要。