【回调消息解决方案】Java手写一个简单的消息存储队列用以存储需要推送的实时数据

一、问题背景

有这种场景:当某一些消息由服务器发送到后台时,往往是在一个回调函数中获取。我们如何从回调函数中获取它并可以由不同的个体创建不同的队列,再将实时获取的消息推送出去呢?

二、方案雏形

一般来说,我们用一个队列存储取得的回调消息,然后在其他我们需要的地方从这个队列中取出消息,由此可以知道需要这么做:
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来将队列名称和队列本身作为键值对,并且对队列和集合加上单独操作和整体操作的方法,在推送实时消息时可以先清空集合,此时集合中存储的就是新收到的消息。重写初始化方法后确保全局只有一个类实例。

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一个简单HashMap实现,仅供参考: ```java public class MyHashMap<K, V> { private static final int DEFAULT_CAPACITY = 16; // 默认容量为16 private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认负载因子为0.75 private int size; // 元素个数 private int threshold; // 阈值,当size >= threshold时,需要进行扩容 private float loadFactor; // 负载因子 private Node<K, V>[] table; // 存储元素的数组 public MyHashMap() { this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); } public MyHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public MyHashMap(int initialCapacity, float loadFactor) { if (initialCapacity <= 0) { throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); } if (loadFactor <= 0 || Float.isNaN(loadFactor)) { throw new IllegalArgumentException("Illegal load factor: " + loadFactor); } this.loadFactor = loadFactor; this.table = new Node[initialCapacity]; this.threshold = (int) (initialCapacity * loadFactor); } public V put(K key, V value) { if (key == null) { return putForNullKey(value); } int hash = hash(key.hashCode()); int index = indexFor(hash, table.length); for (Node<K, V> node = table[index]; node != null; node = node.next) { if (node.hash == hash && (key == node.key || key.equals(node.key))) { V oldValue = node.value; node.value = value; return oldValue; } } addEntry(hash, key, value, index); return null; } private V putForNullKey(V value) { for (Node<K, V> node = table[0]; node != null; node = node.next) { if (node.key == null) { V oldValue = node.value; node.value = value; return oldValue; } } addEntry(0, null, value, 0); return null; } private void addEntry(int hash, K key, V value, int index) { Node<K, V> node = table[index]; table[index] = new Node(hash, key, value, node); if (++size >= threshold) { resize(); } } private void resize() { int oldCapacity = table.length; int newCapacity = oldCapacity * 2; Node<K, V>[] newTable = new Node[newCapacity]; for (Node<K, V> node : table) { while (node != null) { int index = indexFor(node.hash, newCapacity); Node<K, V> next = node.next; node.next = newTable[index]; newTable[index] = node; node = next; } } table = newTable; threshold = (int) (newCapacity * loadFactor); } public V get(K key) { if (key == null) { return getForNullKey(); } int hash = hash(key.hashCode()); int index = indexFor(hash, table.length); for (Node<K, V> node = table[index]; node != null; node = node.next) { if (node.hash == hash && (key == node.key || key.equals(node.key))) { return node.value; } } return null; } private V getForNullKey() { for (Node<K, V> node = table[0]; node != null; node = node.next) { if (node.key == null) { return node.value; } } return null; } public boolean containsKey(K key) { return get(key) != null; } public boolean isEmpty() { return size == 0; } public int size() { return size; } private int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } private int indexFor(int hash, int length) { return hash & (length - 1); } private static class Node<K, V> { private final int hash; private final K key; private V value; private Node<K, V> next; public Node(int hash, K key, V value, Node<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } } } ``` 以上是一个简单的HashMap实现,其中采用了链表法解决哈希冲突,并且在元素个数达到阈值时进行了扩容。需要注意的是,这个实现并不完整,仅作为参考。在实际使用中,还需要考虑并发性、迭代器等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李大有

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值