1.初级采用list结构,采用lpush、rpush实现入队,lpop、rpop实现出队
在客户端(例如Java段),维护一个死循环不停的从队列中读取消息并处理,如果队列中有消息则直接获取到,如果没有消息,就会陷入死循环,直到下一次有消息进入。这种死循环会造成大量的资源浪费。
2.延迟消息队列
zset
有序集合zset和set都是用来存储不重复元素。ZSet根据提供地score参数自动排序,当需要一个不重复且有序地集合列表时,可以选择ZSet,比如说游戏地排行榜。
zset有一个score,用时间作为score,把value存到redis中,通过轮询的方式,不断地读取消息出来。
如果消息是字符串,直接发送即可,如果是一个对象,则需要对对象进行序列化,可以使用JSON实现序列化和反序列化。
首先在项目中添加JSON依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
构造消息对象
public class JavaboyMessage {
private String id;
private Object data;
@Override
public String toString() {
return "JavaboyMessage{" +
"id='" + id + '\'' +
", data=" + data +
'}';
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
封装一个消息队列
public class DelayMsgQueue {
private Jedis jedis;
private String queue;/延迟消息队列DelayMessageQueue
public DelayMsgQueue(Jedis jedis, String queue) {
this.jedis = jedis;
this.queue = queue;
}
/**
* 消息入队
*
* @param data 要发送的消息
*/
public void queue(Object data) {
//构造一个 JavaboyMessage
JavaboyMessage msg = new JavaboyMessage();
msg.setId(UUID.randomUUID().toString());//随机地key
msg.setData(data);//要发送地数据放到
//序列化
try {
String s = new ObjectMapper().writeValueAsString(msg);//序列化消息message
System.out.println("msg publish:" + new Date());
//消息发送,score 延迟 5 秒
jedis.zadd(queue, System.currentTimeMillis() + 5000, s);//添加到队列queue中,
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
/**
* 消息消费
*/
public void loop() {
while (!Thread.interrupted()) {
//读取 score 在 0 到当前时间戳之间的消息
Set<String> zrange = jedis.zrangeByScore(queue, 0,
System.currentTimeMillis(), 0, 1);
if (zrange.isEmpty()) {
//如果消息是空的,则休息 500 毫秒然后继续
try {
Thread.sleep(500);
} catch (InterruptedException e) {
break;
}
continue;
}
//如果读取到了消息,则直接读取消息出来
String next = zrange.iterator().next();
if (jedis.zrem(queue, next) > 0) {
//抢到了,接下来处理业务
try {
JavaboyMessage msg = new ObjectMapper().readValue(next,
JavaboyMessage.class);
System.out.println("receive msg:" + msg);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
}
}
测试
public class DelayMsgTest {
public static void main(String[] args) {
Redis redis = new Redis();
redis.execute(jedis -> {
//构造一个消息队列
**DelayMsgQueue** queue = new DelayMsgQueue(jedis, "javaboy-delayqueue");
//构造消息生产者
Thread producer = new Thread(){
@Override
public void run() {
for (int i = 0; i < 5; i++) {
queue.queue("www.javaboy.org>>>>" + i);
}
}
};
//构造一个消息消费者
Thread consumer = new Thread(){
@Override
public void run() {
queue.loop();
}
};
//启动
producer.start();
consumer.start();
//休息 7 秒后,停止程序
try {
Thread.sleep(7000);
consumer.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}