java自己写一个消息队列_进阶高阶IoT架构-教你如何简单实现一个消息队列

先看一下消息处理中心类(InMemoryStorage)的实现

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import java.util.concurrent.BlockingDeque;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.LinkedBlockingDeque;

/**

@author james mu

@date 2020/7/27 21:47

*/

public final class InMemoryStorage {

//保存消息数据的容器, 键值对

private final ConcurrentHashMap> storage;

private static InMemoryStorage instance;

private InMemoryStorage() {

storage = new ConcurrentHashMap<>();

}

//利用双重检查加锁(double-checked locking),首先检查是否示例已经创建了,如果尚未创建,"才"进行同步。这样以来,只有第一次会同步,这正是我们想要的。

public static InMemoryStorage getInstance() {

if (instance == null) {

synchronized (InMemoryStorage.class) {

if (instance == null) {

instance = new InMemoryStorage();

}

}

}

return instance;

}

//保存消息到主题中,若topic对应的value为空,会将第二个参数的返回值存入并返回

public boolean put(String topic, QueueMsg msg) {

return storage.computeIfAbsent(topic, (t) -> new LinkedBlockingDeque<>()).add(msg);

}

//获得主题中的消息

public List get(String topic) {

//判断map中是否包含此topic

if (storage.containsKey(topic)) {

List entities;

//从此主题对应的阻塞队列中出队一个元素

T first = (T) storage.get(topic).poll();

if (first != null) {

entities = new ArrayList<>();

entities.add(first);

List otherList = new ArrayList<>();

//移动阻塞队列中最大999个元素到arrayList中

storage.get(topic).drainTo(otherList, 999);

for (QueueMsg other : otherList) {

entities.add((T) other);

}

} else {

entities = Collections.emptyList();

}

}

return Collections.emptyList();

}

//删除此map中所有的键值对

public void cleanup() {

storage.clear();

}

}

作为一个消息处理中心中,至少要有一个数据容器用来保存接受到的消息。

Java中的队列(Queue)是提供该功能的一种简单的数据结构,同时为简化队列操作的并发访问处理,我们选择了它的一个子类LinkedBlockingDeque。该类提供了对数据的插入、获取、查询等操作,其底层将数据以链表的形式保存。如果用 offer方法插入数据时队列没满,则数据插入成功,并立 即返回:如果队列满了,则直接返回 false。 如果用 poll方法删除数据时队列不为空, 则返回队 列头部的数据;如果队列为空,则立刻返回 null。

消息格式定义

队列消息接口定义(QueueMsg)

/**

@author james mu

@date 2020/7/27 22:00

*/

public interface QueueMsg {

//消息键

String getKey();

//消息头

QueueMsgHeaders getHeaders();

//消息负载byte数组

byte[] getData();

}

队列消息头接口定义(QueueMsgHeaders)

import java.util.Map;

/**

@author james mu

@date 2020/7/27 21:55

*/

public interface QueueMsgHeaders {

//消息头放入

byte[] put(String key, byte[] value);

//消息头通过key获取byte数组

byte[] get(String key);

//消息头数据全部读取方法

Map getData();

}

队列消息格式(ProtoQueueMsg)

/**

@author jamesmsw

@date 2021/2/19 2:23 下午

*/

public class ProtoQueueMsg implements QueueMsg {

private final String key;

private final String value;

private final QueueMsgHeaders headers;

public ProtoQueueMsg(String key, String value) {

this(key, value, new DefaultQueueMsgHeaders());

}

public ProtoQueueMsg(String key, String value, QueueMsgHeaders headers) {

this.key = key;

this.value = value;

this.headers = headers;

}

@Override

public String getKey() {

return key;

}

@Override

public QueueMsgHeaders getHeaders() {

return headers;

}

@Override

public byte[] getData() {

return value.getBytes();

}

}

默认队列消息头(DefaultQueueMsgHeaders)

import java.util.HashMap;

import java.util.Map;

/**

@author james mu

@date 2020/7/27 21:57

*/

public class DefaultQueueMsgHeaders implements QueueMsgHeaders {

protected final Map data = new HashMap<>();

@Override

public byte[] put(String key, byte[] value) {

return data.put(key, value);

}

@Override

public byte[] get(String key) {

return data.get(key);

}

@Override

public Map getData() {

return data;

}

}

消息生产者

import iot.technology.mqtt.storage.msg.QueueMsg;

import iot.technology.mqtt.storage.queue.QueueCallback;

/**

@author james mu

@date 2020/8/31 11:05

*/

public class Producer {

private final InMemoryStorage storage = InMemoryStorage.getInstance();

private final String defaultTopic;

public Producer(String defaultTopic) {

this.defaultTopic = defaultTopic;

}

public void send(String topicName, T msg) {

boolean result = storage.put(topicName, msg);

}

}

消息消费者

import lombok.extern.slf4j.Slf4j;

import java.util.Collections;

import java.util.List;

import java.util.Set;

import java.util.stream.Collectors;

/**

@author james mu

//虚构函数

public Consumer(String topic) {

this.topic = topic;

stopped = false;

}

public String getTopic() {

return topic;

}

public void subscribe() {

topics = Collections.singleton(topic);

subscribed = true;

}

//批量订阅主题

public void subscribe(Set topics) {

this.topics = topics;

subscribed = true;

}

public void unsubscribe() {

stopped = true;

}

//不断读取topic集合下阻塞队列中的数据集合

public List poll(long durationInMillis) {

if (subscribed) {

List messages = topics

.stream()

.map(storage::get)

.flatMap(List::stream)

.map(msg -> (T) msg).collect(Collectors.toList());

if (messages.size() > 0) {

return messages;

}

try {

Thread.sleep(durationInMillis);

} catch (InterruptedException e) {

if (!stopped) {

log.error("Failed to sleep.", e);

}

}

}

return Collections.emptyList();

}

}

亚马逊测评 www.yisuping.cn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值