畅购商城作业----定时处理订单状态,使用redis延时队列 or使用计划任务类(线程池)

⾃JDK 1.5 开始,JDK提供了 ScheduledThreadPoolExecutor 类⽤于计划任务(⼜称 定时任务),这个类有两个⽤途: 在给定的延迟之后运⾏任务 周期性重复执⾏任务 在这之前,是使⽤ Timer 类来完成定时任务的,但是 Timer 有缺陷: Timer是单线程模式; 如果在执⾏任务期间某个TimerTask耗时较久,那么就会影响其它任务的调 度;Timer的任务调度是基于绝对时间的,对系统时间敏感; Timer不会捕获执⾏TimerTask时所抛出的异常,由于Timer是单线程,所以⼀ 旦出现异常,则线程就会终⽌,其他任务也得不到执⾏。 所以JDK 1.5之后,⼤家就摒弃 Timer ,使⽤ ScheduledThreadPoolExecutor 吧。
1.建立延迟队列线程池,一个核心线程就可以完成任务

   //配置延时任务的线程池
    private final ScheduledExecutorService executorService=new ScheduledThreadPoolExecutor(1,Executors.defaultThreadFactory());

2.使用.scheduleWithFixedDelay方法,20.秒后执行,每5秒从微信查询支付状态

executorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                Order redisOrder = (Order) redisTemplate.boundHashOps("Order").get(order.getId());
                if (redisOrder != null) {
                    Result result = weixinPayFegin.queryStatus(redisOrder.getId());
                    Map<String, String> backMap = (Map<String, String>) result.getData();

                    if (backMap.get("trade_state") != null && backMap.get("trade_state").equals("SUCCESS")) {
                        //这是支付成功
                        updateStatus(backMap.get("out_trade_no"), backMap.get("pay_time"), backMap.get("transaction_id"));
                    } else if (backMap.get("trade_state") != null && (backMap.get("trade_state").equals("NOTPAY") || backMap.get("trade_state").equals("USERPAYING"))) {
                        //这是没有支付
                        redisTemplate.boundHashOps("Order").put(redisOrder.getId(), redisOrder);
                    } else {
                        delete(redisOrder.getId());
                    }
                }
            }
            //20秒之后每5秒检查下回调信息
        },10000 * 2, 5000,TimeUnit.SECONDS);

下面我说一下怎么使用redis延时队列
延迟队列可以通过 zset 来实现,因为 zset 中有一个 score,我们可以把时间作为 score,将 value 存到 redis 中,然后通过轮询的方式,去不断的读取消息出来。如果消息是一个字符串,直接发送即可,如果是一个对象,则需要对 对象进行序列化,使用 JSON 来实现序列化和反序列化。
1 封装消息

public class Message {
    private String id;
    private Object data;

    @Override
    public String toString() {
        return "Message{" +
                "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;
    }
}

2 封装一个消息队列:
public class DelayMsgQueue {
private Jedis jedis;

private String queue;


public DelayMsgQueue(Jedis jedis, String queue) {
    this.jedis = jedis;
    this.queue = queue;
}
/**
 * 消息入队
 * @param data 要发送的消息
 */
public void queue(Object data)  {
    //构造一个 Message
    Message msg=new Message();
    msg.setId(UUID.randomUUID().toString());
    msg.setData(data);

    //序列化
    try {
        String s = new ObjectMapper().writeValueAsString(msg);

        System.out.println("msg push"+new Date());

        jedis.zadd(queue,System.currentTimeMillis()+5000,s);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}

/**
 * 消息消费
 */
public void loop()  {
    while(!Thread.interrupted()){
        //读取 score 在 0 到当前时间戳之间的消息
        Set<String> zrange = jedis.zrangeByScore(queue, 0, System.currentTimeMillis(), 0, 1);

        while(zrange.isEmpty()){
            //如果消息是空的,则休息 500 毫秒然后继续
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            continue;
        }

        //如果读取到了消息,则直接读取消息出来
        String next = zrange.iterator().next();
         //Redis Zrem 命令用于移除有序集中的一个或多个成员,不存在的成员将被忽略。
        //ZREM的返回值进行判断,只有大于0的时候,才消费数据,避免并发多消费
        if(jedis.zrem(queue,next)>0){
               //抢到了处理业务
            try {
                Message msg = new ObjectMapper().readValue(next, Message.class);

                System.out.println("receive msg:" + msg);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }
}

}

3测试

Jedis jedis = new Jedis("××××8×××");
        //构造一个消息队列
            DelayMsgQueue queue = new DelayMsgQueue(jedis,"delay-queue");
            //构造消息生产者
            Thread producer = new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 5; i++) {
                        queue.queue("www.changgou.com>>>>" + 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();
            }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值