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  设置过期时间

 

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

 

posted @ 2019-06-28 15:18  农夫与蛇丶  阅读(7891)  评论(1编辑  收藏  举报