一、问题背景
有这种场景:当某一些消息由服务器发送到后台时,往往是在一个回调函数中获取。我们如何从回调函数中获取它并可以由不同的个体创建不同的队列,再将实时获取的消息推送出去呢?
二、方案雏形
一般来说,我们用一个队列存储取得的回调消息,然后在其他我们需要的地方从这个队列中取出消息,由此可以知道需要这么做:
1、这个队列由于经常增减,应该是链表形式的
2、这个队列应该只有一个实例,这样才能在其他地方取出消息
3、当存在多条消息同时向队列存入的情况时,它应该保持原子性
以下代码来自这篇博客:https://blog.csdn.net/weixin_40035204/article/details/80094352?utm_source=blogxgwz2
由此我们可以用以下这种方式解决:
/**
* @author LiHang
* @date 2020-09-08
* @description 用于存储消息的缓存队列,可将mqtt回调类的消息传递给用户
*/
public class MessageQueue {
private static final Logger log = LoggerFactory.getLogger(MessageQueue.class);
private LinkedList<String> list = new LinkedList<String>();
private int size = 0;
private static MessageQueue instance;
/**
* 初始化方法,确保只存在一个类实例
*/
public static synchronized MessageQueue getInstance(){
if (instance == null){
instance = new MessageQueue();
}
return instance;
}
/**
* 添加一条消息
*/
public synchronized void put(String ms){
size++;
list.addLast(ms);
log.info("放入了一条消息:{}",ms);
}
/**
* 返回并删除第一条消息
*/
public synchronized String get(){
size--;
return list.removeFirst();
}
/**
* 判断为空
*/
public synchronized boolean empty(){
boolean flag = false;
if (size == 0){
flag = true;
}
return flag;
}
/**
* 获取长度
*/
public synchronized int getSize(){
return size;
}
/**
* 清空队列
*/
public synchronized void clear(){
list.clear();
size = 0;
}
}
三、根据需求优化
目前我们接收到的消息需要分开存储到属于自己的队列中,并且推送的时候需要推送实时数据,而上面的代码只能取到历史的数据,那么就不能使用上面的代码了,需要自己根据需求做一些改变。
改动如下:
/**
* @author LiHang
* @date 2020-09-08
* @description 用于存储mqtt消息的消息队列,可将mqtt回调类的消息传递给用户
*/
public class MessageQueue {
private static final Logger log = LoggerFactory.getLogger(MessageQueue.class);
private LinkedList<String> list = new LinkedList<String>();
private int size = 0;
public static ConcurrentHashMap<String,MessageQueue> queueMap;
/**
* 初始化方法,确保每个topic只对应一个类实例
*/
public static synchronized MessageQueue getInstance(String topic){
if (queueMap == null){
queueMap = new ConcurrentHashMap<>(8);
}
if (!queueMap.containsKey(topic)){
queueMap.put(topic,new MessageQueue());
}
return queueMap.get(topic);
}
/**
* 移除集合中某个订阅主题
*/
public static synchronized void removeQueue(String topic){
queueMap.remove(topic);
}
/**
* 清空集合中所有队列
*/
public static synchronized void clearAll(){
queueMap.clear();
}
/**
* 添加一条消息
*/
public synchronized void put(String ms){
size++;
list.addLast(ms);
log.info("放入了一条消息:{}",ms);
}
/**
* 返回并删除第一条消息
*/
public synchronized String get(){
size--;
return list.removeFirst();
}
/**
* 判断为空
*/
public synchronized boolean empty(){
boolean flag = false;
if (size == 0){
flag = true;
}
return flag;
}
/**
* 获取长度
*/
public synchronized int getSize(){
return size;
}
/**
* 清空队列
*/
public synchronized void clear(){
list.clear();
size = 0;
}
}
我们初始化一个Map来将队列名称和队列本身作为键值对,并且对队列和集合加上单独操作和整体操作的方法,在推送实时消息时可以先清空集合,此时集合中存储的就是新收到的消息。重写初始化方法后确保全局只有一个类实例。