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 设置过期时间
延时两秒 在工程控制太看到输出