redis 延时队列
实现思路
方式一
1. 使用redis zset 数据结构 2.使用score排序 score为过期时间点 3.启动线程不断取出排序第一个 比较score和当前时间点 如果score小于或等于当前时间 说明此数据过期 需要处理 4.处理完毕在zset中移除
public class TestMain {
private static final String ADDR="39.96.77.182";
private static final int PORT=6379;
//初始化jedis
private static JedisPool jedisPool=new JedisPool(new GenericObjectPoolConfig(),ADDR,PORT,10000);
public static Jedis getJedis() {
return jedisPool.getResource();
}
//消息入队
public void productionDelayMessage(){
//延迟5秒
Calendar cal1 = Calendar.getInstance();
cal1.add(Calendar.SECOND, 5);
int second3later = (int) (cal1.getTimeInMillis() / 1000);
Long orderId = TestMain.getJedis().zadd("OrderId", second3later, "OID0000001" );
System.out.println(new Date()+"ms:redis生成了一个订单任务:订单ID为"+"OID0000001"+"==============="+orderId);
}
//消费者取订单
public void consumerDelayMessage(){
Jedis jedis = TestMain.getJedis();
while(true){
Set<Tuple> items = jedis.zrangeWithScores("OrderId", 0, 1);
if(items == null || items.isEmpty()){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
continue;
}
int score = (int) ((Tuple)items.toArray()[0]).getScore();
Calendar cal = Calendar.getInstance();
int nowSecond = (int) (cal.getTimeInMillis() / 1000);
if(nowSecond >= score){
String orderId = ((Tuple)items.toArray()[0]).getElement();
Long num = jedis.zrem("OrderId", orderId);
System.out.println(num);
if( num != null && num>0){
System.out.println(new Date() +"ms:redis消费了一个任务:消费的订单OrderId为"+orderId);
}
}
}
}
public static void main(String[] args) {
TestMain appTest =new TestMain();
appTest.productionDelayMessage();
appTest.consumerDelayMessage();
}
执行结果

方式二: redis过期回调
修改redis 配置 redis.conf 添加notify-keyspace-events Ex

编写测试demo
新建boot工程 加入redis依赖
新建redisconfig 注入 RedisMessageListenerContainer Bean
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
编写redis 监听类 继承KeyExpirationEventMessageListener
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = message.toString();
System.out.println("监听到过期的key为:"+expiredKey);
}
}
运行boot工程 使用redis 客户端 redis desktop manager添加一个key 设置过期时间

延时两秒 在工程控制太看到输出

浙公网安备 33010602011771号