1、BlockingQueue
BlockingQueue就是阻塞队列,向其插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;取出数据时,如果队列已空,线程将会阻塞等待直到队列非空。当然了,作为队列,它也是先进先出的。
BlockingQueue的接口:
接口 | 说明 |
---|---|
.add(Object o) | 插入数据,如果超过队列长度,抛出异常 |
.offer(Object o, long timeout, TimeUnit unit) | 插入数据,如果超过队列长度,等待timeout时间,在时间内队列有空则插入数据,超时则返回false |
.put(Object o) | 插入数据,如果超过队列长度,阻塞线程,直到可以加入数据 |
.poll(Object o, long timeout, TimeUnit unit) | 取出数据,若队列为空,等待timeout时间,在时间内队列中有数据则取出,否则返回null |
.take(Object o) | 取出数据,如果队列为空,阻塞线程,直到有数据可取 |
.remove() | 取出数据,若队列为空,抛出异常 |
2、生产者消费者模式
生产者消费者模式由生产者、消费者和一块共享数据区组成。生产者用于生产数据,消费者用于消费数据,在这种模式中BlockingQueue就可以作为共享数据区,作为两者间通信的队列。
实际应用:
最近用到这个是将sip协议封装成restful接口供别人调用,类似别人调用本组件接口->组件通过sip协议方式调用设备->接收设备返回信息->返回给调用者。看起来也可以使用同步方法,但是实际上在处理设备返回信息的时候是直接长期监听了一个端口,并不是在别人调用之后才触发的,因此监听到了返回信息之后需要想办法通知,在这里监听到消息之后的步骤中就可以生产消息,而供别人调用的接口中可以消费数据。
(题外话 这里长期监听是因为设备还会有注册、保活等消息发过来,如果有人有处理上面的情况更好的方式也可以告知我,非常感谢)
3、在Spring Boot项目中使用
在SpringBoot中使用十分方便,只需要建一个类存放BlockingQueue:
@Component
public class SipResponseQueue {
/**设备状态查询返回消息队列*/
private static final BlockingQueue<String> DEVICE_STATUS_QUEUE = new ArrayBlockingQueue<>(300);
public void produceDeviceStatus(String responseInfo) throws SchedulerException {
try {
DEVICE_STATUS_QUEUE.put(responseInfo);
} catch (InterruptedException e) {
……
}
}
public String consumeDeviceStatus() throws SchedulerException {
try {
return DEVICE_STATUS_QUEUE.poll(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
……
}
return null;
}
}
然后在需要生产数据和消费数据的地方分别调用sipResponseQueue.produceXxx()和consumeXxx即可。