DelayQueue——延时队列做定时任务

本文介绍了一个Java类,实现ItemDelayed,用于在指定时间后执行任务,并讨论了如何通过BroadcastThread使用DelayQueue进行任务调度,同时考虑了断电情况下数据持久化策略。
@Data
public class ItemDelayed implements Delayed {
    private Long id;
    //触发时间
    private long time;
    //内容
    private String body;

    public ItemDelayed(){

    }
    public ItemDelayed(Long id,long time,String body, TimeUnit unit) {
        this.id = id;
        this.body = body;
        this.time = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS) + System.nanoTime();
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return time - System.currentTimeMillis();
    }

    @Override
    public int compareTo(Delayed o) {
        ItemDelayed item = (ItemDelayed) o;
        long diff = this.time - item.time;
        if (diff <= 0) {
            return -1;
        }else {
            return 1;
        }
    }
}
@Slf4j
public class BroadcastThread implements Runnable{
    private DelayQueue<ItemDelayed> delayQueue;
    @Autowired(required = false)
    private BroadcastMapper broadcastMapper;

    /**
     * 封装queue
     * @param id 任务ID
     * @param duration 时长(天)
     * @param body 标题
     * @return
     */
    public BroadcastThread(Long id,Integer duration,String body){
        this.delayQueue = new DelayQueue();
        ItemDelayed item = new ItemDelayed();
        item.setId(id);
        item.setBody(body);
        Long exeTime = CommonTypeSwitch.getTimestampOfDateTime(LocalDateTime.now().plusDays(duration));
        item.setTime(exeTime);
        this.delayQueue.offer(item);
    }

    public BroadcastThread(DelayQueue<ItemDelayed> delayQueue){
        this.delayQueue = delayQueue;
    }


    @Override
    public void run() {
        while (true) {
            try {
                ItemDelayed take = delayQueue.take();
                log.info("消费消息id:" + take.getId()+ " 消息体:" + take.getBody());
                //道具服务时间过期,修改广播列表 该任务等广播状态置为失效
                Broadcast entity = broadcastMapper.queryByTaskId(take.getId(),StatusEnum.BroadcastStatus.PROCESSING.getCode(),
                        StatusEnum.DflagStatus.VALID.getCode());
                if (null != entity){
                    Broadcast record = new Broadcast();
                    record.setStatus(StatusEnum.BroadcastStatus.OVER.getCode());
                    record.setId(entity.getId());
                    record.setUpdateTime(new Date());
                    record.setUpdateBy(ConstantValue.L_ZERO);
                    broadcastMapper.updateByPrimaryKeySelective(record);
                }
            } catch (InterruptedException e) {
                log.error("error:",e);
            }
        }
    }
}

如果发生断电情况,导致数据丢失,可以加上数据库,把需要发到延时队列到数据都存到数据库+版本(防止重复消费),每次重启项目扫描数据填充到队列里,删除数据库失败的不进行业务处理,或者先业务处理,删除失败回滚业务(业务也要有版本,防止重复操作)

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值