java 简单实现延时队列 DelayQueue

编写了个简单的电商下单 延时取消的示例

Delayed
public class Delayed implements java.util.concurrent.Delayed {

    /**
     * 记录id 订单id
     */
    private Integer id;

    public Integer getId() {
        return id;
    }


    /**
     * 开始时间
     */
    private long start = System.currentTimeMillis();
    /**
     * 多少秒后到期
     */
    private long time ;

    public Delayed(Integer id,long time) {
        this.id = id;
        this.time = time;
    }

    /**
     *方法中,返回与此对象关联的剩余延迟
     *给定时间单位
     *
     * @param unit 时间单位
     * @return 剩余延迟;零或负值表示
     * that the delay has already elapsed
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert((start+time) - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    /**
     * 用于延迟队列内部比较排序   当前时间的延迟时间 - 比较对象的延迟时间
     * @param o
     * @return
     */
    @Override
    public int compareTo(java.util.concurrent.Delayed o) {
        Delayed o1 = (Delayed) o;
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
    }

    @Override
    public String toString() {
        return "OrderDelayed{" +
                ", start=" + start +
                ", id=" + id +
                ", time=" + time +
                '}';
    }
}
DelayedVo
@Data
@ToString
public class DelayedVo implements Serializable {
    /**
     * 记录id 订单id
     */
    private Integer id;

    /**
     * 需要倒计时时间挫
     */
    private Long time;
}
DelayQueue
@Slf4j
@Component
public class XiaoDelayQueue implements CommandLineRunner {

    /**
     * 线程池核心线程数
     */
    private static final int COREPOOLSIZE = 10;
    /**
     * 最大线程数
     */
    private static final int MAXPOOLSIZE = 10;
    /**
     * 保存最大时间
     */
    private static final int KEEPALIVESECONDS = 60;
    /**
     * 最大延时队列
     */
    private static final int DELAYQUEUESIZE = 1000;


    private static final String ORDER = "goods_time";

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private OrderService orderService;

    private DelayQueue<Delayed> delayQueue = new DelayQueue();

    private ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

    /**
     * 加入到延时队列中
     *
     * @param delayed
     */
    public void put(Delayed delayed) {
        log.info("加入延时任务:{}", delayed);
        delayQueue.put(delayed);
    }

    /**
     * 取消延时任务
     *
     * @param delayed
     * @return
     */
    public boolean remove(Delayed delayed) {
        log.info("取消延时任务:{}", delayed);
        return delayQueue.remove(delayed);
    }


    public void getDelayed() {
        log.info("开始获取延时任务");
        while (true) {
            //加数量限制 可以让其它微服务分担
            if (delayQueue.size() <= DELAYQUEUESIZE) {
                Object o = redisUtil.rightPop(ORDER);
                if (!StringUtils.isEmpty(o)) {
                    log.info("延时任务获取====>{}", o.toString());
                    DelayedVo delayedVo = JsonUtil.fromJson(o.toString(), DelayedVo.class);
                    put(new Delayed(delayedVo.getId(), delayedVo.getTime()));
                }
            }
        }
    }

    @Override
    public void run(String... args) {
        log.info("初始化Executor");
        asyncServiceExecutor();
        log.info("初始化getDelayed");
        executor.execute(new Thread(this::getDelayed));
        //多线程执行
        for (int i = 0; i <= COREPOOLSIZE - 1; i++) {
            log.info("初始化excuteThread");
            executor.execute(new Thread(this::excuteThread));
        }
    }


    private Executor asyncServiceExecutor() {
        // 设置核心线程数
        executor.setCorePoolSize(COREPOOLSIZE);
        // 设置最大线程数
        executor.setMaxPoolSize(MAXPOOLSIZE);
        //配置队列大小
        executor.setQueueCapacity(Integer.MAX_VALUE);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(KEEPALIVESECONDS);
        // 设置默认线程名称
        executor.setThreadNamePrefix("订单延时检查线程池");
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //执行初始化
        executor.initialize();
        return executor;
    }

    /**
     * 延时任务执行线程
     */
    public void excuteThread() {
        log.info("执行延时任务");
        while (true) {
            try {
                Delayed delayed = delayQueue.take();
                cancelOrderInfo(delayed);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 队列更改状态
     *
     * @param delayed
     */
    private void cancelOrderInfo(Delayed delayed) {
        log.info("开始执行延时任务");
        //调用取消订单方法
        orderService.cancelOrder(delayed.getId());
    }
}
OrderService
public interface OrderService {

    /**
     * 下单
     * @param placeAnOrderBo
     * @param userTokenVo
     * @return
     */
    Object placeAnOrder(String goodsId, String userId) throws IOException;

    /**
     * 队列取消订单
     * @param id
     */
    void cancelOrder(Integer id);

    /**
     *  手动取消订单
     * @param orderId
     * @return
     */
    Object manualCancelOrder(Integer orderId);

}
OrderServiceImpl
@Slf4j
@Service
public class OrderServiceImpl  implements OrderService {
    @Resource
    private DelayQueue delayQueue;
    @Resource
    private RedisUtil redisUtill;
    private static final String ORDER = "goods_time";


    @Override
    public Object placeAnOrder(String gameId, String userId) throws IOException {
        UserInfo userInfo = userInfoService.getById(userId);
        GoodsInfo goodsInfo = goodsInfoService.getById(gameId);
        //生成订单
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setUserId(userInfo.getUserId());
        orderRecord.setGoodsId(goodsInfo.getGoodsId());
        Long orderNo = System.currentTimeMillis();
        orderRecord.setOrderCode(userInfo.getUserId() +orderNo.toString());
        //15分钟
        long time = 60 * 1000 * 15;
        //计算过期时间
        long expiration = date.getTime() + time;
        //保存过期时间
        orderRecord.setExpiration(new Date(expiration));
        // 1.未付款 2.未发货 3.失效 4.已发货 5.取消订单
        orderRecord.setOrderStates(DealConstant.ORDER_STATUS_1);
        orderRecordMapper.insert(orderRecord);
        //加入队列
        Push(orderRecord.getOrderId(),time);
        return "下单成功";
    }


    @Override
    public void cancelOrder(Integer id) {
        OrderRecord orderRecord = orderRecordMapper.selectById(id);
        log.info("id:{}",id);
        if (orderRecord.getOrderStates() != DealConstant.ORDER_STATUS_1){
            return "订单已操作";
        }
        Integer states = orderRecord.getOrderStates();
        //更改订单状态
        // 1.未付款 2.未发货 3.失效 4.已发货 5.取消订单
        orderRecord.setOrderStates(DealConstant.ORDER_STATUS_3);
        log.info("目前状态:{}",states);
        orderRecordMapper.update(orderRecord,new LambdaQueryWrapper<OrderRecord>()
                .eq(OrderRecord :: getOrderId,id)
                .eq(OrderRecord :: getOrderStates , states));
        log.info("id:{}",orderRecord.getOrderId());
        log.info("修改后状态:{}",orderRecord.getOrderStates());
    }

    @Override
    public Object manualCancelOrder(Integer orderId) {
        OrderRecord orderRecord = orderRecordMapper.selectById(orderId);
        //更改订单状态
        // 1.未付款 2.未发货 3.失效 4.已发货 5.取消订单
        orderRecord.setOrderStates(DealConstant.ORDER_STATUS_5);
        orderRecordMapper.updateById(orderRecord);
        long time = orderRecord.getExpiration().getTime() - date.getTime();
        LRemove(orderId,time);
        return "取消成功";
    }


    /**
     * 加入队列
     *
     * @param id
     * @param time
     */
    private void Push(Integer id, long time) {
        DelayedVo delayedVo = new DelayedVo();
        delayedVo.setId(id);
        delayedVo.setTime(time);
        log.info("加入队列:{},》》》{}",delayedVo.getTime(),id);
        redisUtill.leftPush(ORDER, JsonUtil.toJson(delayedVo));
    }

    /**
     * 移除队列
     *
     * @param id
     * @param time
     */
    private void LRemove(Integer id, long time) {
        DelayedVo delayedVo = new DelayedVo();
        //计算延迟时间
        delayedVo.setId(id);
        delayedVo.setTime(time);
        redisUtill.lRemove(ORDER, -1, JsonUtil.toJson(delayedVo));
        xiaoDelayQueue.remove(new Delayed( id, time));
    }
}

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的DelayQueue是一个特殊的队列,它只允许在指定的延迟时间之后才能从队列中取出元素。可以使用DelayQueue实现一些延迟任务的功能,例如任务调度、缓存过期等。 DelayQueue基于PriorityQueue实现,但是它的元素必须实现Delayed接口,Delayed接口中定义了一个getDelay()方法,返回元素的延迟时间。 当从DelayQueue中取出元素时,如果该元素的延迟时间还没有到达,则该元素会被重新加入队列中,直到延迟时间到达。 以下是一个简单的使用DelayQueue的例子: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class DelayQueueExample { public static void main(String[] args) throws InterruptedException { DelayQueue<DelayedElement> delayQueue = new DelayQueue<DelayedElement>(); delayQueue.add(new DelayedElement("element1", 2000)); delayQueue.add(new DelayedElement("element2", 5000)); delayQueue.add(new DelayedElement("element3", 1000)); while (!delayQueue.isEmpty()) { DelayedElement element = delayQueue.take(); System.out.println("Taking element: " + element); } } static class DelayedElement implements Delayed { private String name; private long delayTime; public DelayedElement(String name, long delayTime) { this.name = name; this.delayTime = System.currentTimeMillis() + delayTime; } @Override public long getDelay(TimeUnit unit) { long diff = delayTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { if (this.delayTime < ((DelayedElement) o).delayTime) { return -1; } if (this.delayTime > ((DelayedElement) o).delayTime) { return 1; } return 0; } @Override public String toString() { return "DelayedElement{" + "name='" + name + '\'' + ", delayTime=" + delayTime + '}'; } } } ``` 在上面的例子中,我们创建了一个DelayQueue,并向其中添加了三个DelayedElement元素。每个元素都有一个延迟时间,分别为2秒、5秒和1秒。 在主线程中,我们不断地从DelayQueue中取出元素,直到队列为空。当元素的延迟时间还没有到达时,它会被重新加入队列中,直到延迟时间到达。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值