Java 开发 - 简单消息队列实现、主题消息队列实现

简单消息队列

1、MessageQueue
  • SimpleMessageQueue.java
java 复制代码
public class SimpleMessageQueue<T> {

    private final BlockingQueue<T> queue;
    private final ExecutorService executor = Executors.newCachedThreadPool();
    private volatile boolean running = true;

    public SimpleMessageQueue(int capacity) {
        this.queue = new ArrayBlockingQueue<>(capacity);
    }

    // 获取队列大小
    public int size() {
        return queue.size();
    }

    // 停止队列
    public void stop() {
        running = false;
        executor.shutdownNow();
    }

    // 发送消息
    public boolean send(T message) {
        return queue.offer(message);
    }

    // 发送消息,如果队列已满,则阻塞
    public void sendBlocking(T message) throws InterruptedException {
        queue.put(message);
    }

    // 消费消息
    public void consume(Consumer<T> consumer) {
        executor.submit(() -> {
            while (running && !Thread.currentThread().isInterrupted()) {
                try {
                    T message = queue.take();
                    consumer.accept(message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
        });
    }
}
2、Test
java 复制代码
SimpleMessageQueue<String> simpleMessageQueue = new SimpleMessageQueue<>(10);

// 消费者
simpleMessageQueue.consume(message -> {
    System.out.println("consumer receive: " + message);

    // 模拟消费时间
    try {
        Thread.sleep(2 * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

// 生产者
for (int i = 0; i < 5; i++) {

    // 模拟生产时间
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    try {
        String message = "message" + (i + 1);
        simpleMessageQueue.sendBlocking(message);
        System.out.println("producer send: " + message);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
复制代码
# 输出结果

producer send: message1
consumer receive: message1
producer send: message2
consumer receive: message2
producer send: message3
producer send: message4
consumer receive: message3
producer send: message5
consumer receive: message4
consumer receive: message5
java 复制代码
SimpleMessageQueue<String> simpleMessageQueue = new SimpleMessageQueue<>(10);

for (int i = 0; i < 5; i++) {
    String producerId = "producer" + (i + 1);
    new Thread(() -> {

        // 生产者
        for (int j = 0; j < 3; j++) {

            // 模拟生产时间
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            try {
                String message = producerId + " - message" + (j + 1);
                simpleMessageQueue.sendBlocking(message);
                System.out.println(producerId + " send: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

// 消费者
simpleMessageQueue.consume(message -> {
    System.out.println("consumer receive: " + message);

    // 模拟消费时间
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
复制代码
# 输出结果

producer2 send: producer2 - message1
producer5 send: producer5 - message1
producer4 send: producer4 - message1
producer3 send: producer3 - message1
consumer receive: producer5 - message1
producer1 send: producer1 - message1
producer5 send: producer5 - message2
producer4 send: producer4 - message2
producer2 send: producer2 - message2
producer3 send: producer3 - message2
producer1 send: producer1 - message2
consumer receive: producer3 - message1
producer5 send: producer5 - message3
producer4 send: producer4 - message3
consumer receive: producer4 - message1
producer2 send: producer2 - message3
consumer receive: producer2 - message1
producer1 send: producer1 - message3
consumer receive: producer1 - message1
producer3 send: producer3 - message3
consumer receive: producer5 - message2
consumer receive: producer4 - message2
consumer receive: producer2 - message2
consumer receive: producer3 - message2
consumer receive: producer1 - message2
consumer receive: producer5 - message3
consumer receive: producer4 - message3
consumer receive: producer2 - message3
consumer receive: producer1 - message3
consumer receive: producer3 - message3

主题消息队列

1、MessageQueue
  • TopicMessageQueue.java
java 复制代码
public class TopicMessageQueue<T> {

    private final Map<String, Map<Consumer<T>, BlockingQueue<T>>> topicMap = new ConcurrentHashMap<>();
    private final ExecutorService executor = Executors.newCachedThreadPool();
    private final int queueCapacity;

    public TopicMessageQueue(int queueCapacity) {
        this.queueCapacity = queueCapacity;
    }

    public void stop() {
        executor.shutdownNow();
    }

    // 发布消息到主题
    public void publish(String topic, T message) {
        Map<Consumer<T>, BlockingQueue<T>> queueMap = topicMap.get(topic);
        if (queueMap == null) {
            return;
        }
        for (BlockingQueue<T> queue : queueMap.values()) {
            queue.offer(message);
        }
    }

    // 订阅主题
    // 允许一个消费者订阅多个主题
    // 不允许一个消费者订阅重复订阅同一个主题
    public void subscribe(String topic, Consumer<T> consumer) {
        Map<Consumer<T>, BlockingQueue<T>> queueMap = topicMap.get(topic);

        if (queueMap == null) {

            // 如果 queueMap 为 null,说明还没有任何消费者订阅该主题
            // 不需要检查当前消费者是否已经订阅了该主题

            queueMap = new ConcurrentHashMap<>();
            topicMap.put(topic, queueMap);
        } else {

            // 如果 queueMap 不为 null,说明已经有消费者订阅了该主题
            // 需要检查当前消费者是否已经订阅了该主题

            if (queueMap.containsKey(consumer)) {
                return;
            }
        }

        BlockingQueue<T> queue = new LinkedBlockingQueue<>(queueCapacity);
        queueMap.put(consumer, queue);

        executor.submit(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    T message = queue.take();
                    consumer.accept(message);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
    }

    // 取消订阅主题
    public void unsubscribe(String topic, Consumer<T> consumer) {
        Map<Consumer<T>, BlockingQueue<T>> queueMap = topicMap.get(topic);
        if (queueMap == null) {
            return;
        }
        queueMap.remove(consumer);
    }
}
2、Test
java 复制代码
TopicMessageQueue<String> topicMessageQueue = new TopicMessageQueue<>(10);

// 消费者
Consumer<String> consumer1 = message -> System.out.println("consumer1 收到消息: " + message);
Consumer<String> consumer2 = message -> System.out.println("consumer2 收到消息: " + message);
Consumer<String> consumer3 = message -> System.out.println("consumer3 收到消息: " + message);

// 订阅主题
topicMessageQueue.subscribe("sports", consumer1);
topicMessageQueue.subscribe("sports", consumer2);
topicMessageQueue.subscribe("news", consumer3);
topicMessageQueue.subscribe("news", consumer1);

// 发布消息
topicMessageQueue.publish("sports", "篮球比赛开始");
topicMessageQueue.publish("news", "今日头条新闻");
topicMessageQueue.publish("sports", "足球比赛结果");

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

// 取消订阅
topicMessageQueue.unsubscribe("sports", consumer1);

topicMessageQueue.publish("sports", "这条消息只有 consumer2 能收到");

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

topicMessageQueue.stop();
复制代码
# 输出结果

consumer3 收到消息: 今日头条新闻
consumer1 收到消息: 篮球比赛开始
consumer2 收到消息: 篮球比赛开始
consumer1 收到消息: 今日头条新闻
consumer2 收到消息: 足球比赛结果
consumer1 收到消息: 足球比赛结果
consumer2 收到消息: 这条消息只有 consumer2 能收到
相关推荐
从琳开始989几秒前
从Socket到UDP回显服务器:Java网络编程完整指南
java·网络·网络协议·udp·java-ee
SZYSK8 分钟前
OpenHarmony 上读卡、推理和双屏刷新抢 CPU:核验机与消费机的调度差
物联网·算法·harmonyos·1024程序员节
软件技术NINI15 分钟前
基于SpringBoot和Vue的摇滚乐鉴赏网站
vue.js·spring boot·后端·spring·html·毕业设计·毕设
ShineWinsu21 分钟前
对于Qt:QPushButton常见属性的解析
开发语言·c++·qt·api·gui·按钮·qpushbutton
外贸GEO优化22 分钟前
外贸独立站的可抓取性:JS 渲染、懒加载与无限滚动到底影响什么
开发语言·javascript·ecmascript
飞浪纪元[FWC–FE]22 分钟前
Qt 工程创建与 CMake / qmake 构建规范
开发语言·数据库·qt
Ivanqhz26 分钟前
MoE + LLM 应用
数据库·人工智能·pytorch·python·深度学习·算法·1024程序员节
Tsuki_tl32 分钟前
【总结】Redis五大数据类型应用场景及基本命令
数据库·redis·后端·缓存·缓存中间件·redis命令·redis 五大数据类型
后台模板学习35 分钟前
Go Web开发中任务调度框架的源码解析与高可用实现方案
开发语言·后端·golang