延迟队列发布

1、利用延迟队列

延时队列,第一他是个队列,所以具有对列功能第二就是延时,这就是延时对列,功能也就是将任务放在该延时对列中,只有到了延时时刻才能从该延时对列中获取任务否则获取不到……

应用场景比较多,比如延时1分钟发短信,延时1分钟再次执行等,下面先看看延时队列demo之后再看延时队列在项目中的使用:

/**
 *延迟队列消息体
 *消息体定义 实现Delayed接口就是实现两个方法即compareTo 和 getDelay最重要的就是getDelay			   方法,
   这个方法用来判断是否到期…… */
 */
@Log4j
@Data
public class DelayMessage implements Delayed {

	private Long orderId;
	/**
     * 运行日期,转化成毫秒值  延迟时长,这个是必须的属性因为要按照这个判断延时时长。
	 */
	private long executeTime;

	private int times;

	private DelayMessage() {}

	public DelayMessage(Long orderId, long executeTime) {
		this(orderId,executeTime,0);
	}

	public DelayMessage(Long orderId, long executeTime, int times){
		this.orderId = orderId;
		this.executeTime =  executeTime;
		this.times = times;
	}

	@Override
	public int compareTo(Delayed o) {
		DelayMessage dm = (DelayMessage) o;
		return dm.getExecuteTime() > this.executeTime ? -1 : (dm.getExecuteTime() == this.executeTime ? 0 : 1);
	}

	/**
	 * 单位:毫秒
	 */
	@Override
	public long getDelay(TimeUnit unit) {
		try {
			// 0.5秒检查一次
			Thread.sleep(500);
		} catch (InterruptedException e) {
			log.error("getDelay Interrupted",e);
			Thread.currentThread().interrupt();
		}
        return executeTime - System.currentTimeMillis();
	}
}

########################################################

/**
 *
 * @author
 */
@Component
public class DelayQueueExecutor {

	@Autowired
	private OrderSignCountdownCache orderSignCountdownCache;

	@Autowired
	private OrderService orderService;

	@Autowired
	private OrderTransactionService orderTransactionService;

	/**
	 * 全局延时队列
	 */
	private static DelayQueue<DelayMessage> queue = new DelayQueue<DelayMessage>();

	/**
	 * 延时队列 添加数据
	 * 
	 * @param orderId 订单号
	 * @param timeOut 触发时间
	 */
	public static void putDelayQueue(Long orderId,Long timeOut) {
		queue.put(new DelayMessage(orderId , timeOut));
	}

	/**
	 * 延时队列 添加数据
	 *
	 * @param orderId 订单号
	 * @param timeOut 触发时间
	 */
	static void putDelayQueue(Long orderId,Long timeOut,int times) {
		queue.put(new DelayMessage(orderId , timeOut));
	}

	/**
	 * 启动延时队列消费者
	 */
	@PostConstruct
	private void initThread() {
		Function<Long,Object> task = new Function<Long,Object> () {
			@Override
			public Object apply(Long orderId) {
				Order order = orderService.getOrderById(orderId, null);
				if(EnumOrderStatus.WAIT_SIGN.getKey().equals(order.getOrderStatus())){
					return orderTransactionService.doUpdateOrderStatusToCancel("超期未签章",order);
				}
				return null;
			}
		};
		new Thread(new MessageConsumer(queue,orderSignCountdownCache,task)).start();
		new Thread(new MessageConsumer(queue,orderSignCountdownCache,task)).start();
	}
}

########################################################

/**
 * @author 
 */
public interface Function<T, R> {
    /**
     * Function
     * @see "java.util.function.Function"
     * @param t t
     * @return R
     */
    R apply(T t);
}

########################################################

/**
 * @author 
 */
@Slf4j
public class MessageConsumer implements Runnable {

    /**
     * 延时队列 ,消费者从其中获取消息进行消费
	 */
	private DelayQueue<DelayMessage> queue;

	private OrderSignCountdownCache orderSignCountdownCache;

	private Function<Long,Object> task;

	MessageConsumer(DelayQueue<DelayMessage> queue, OrderSignCountdownCache orderSignCountdownCache, Function<Long,Object> task) {
		this.queue = queue;
		this.orderSignCountdownCache = orderSignCountdownCache;
		this.task = task;
	}
	
	@Override
	public void run() {
		DelayMessage msg = null;
		while (true) {
			try {
				msg = queue.take();
				//  可以调整为异步调用 
				Long orderId = msg.getOrderId();
				boolean isSuccess = orderSignCountdownCache.del(orderId);
				if(isSuccess) {
					log.info("抢数据 success:" + orderId);
					// 取消订单业务代码
					task.apply(orderId);
				}
			} catch (InterruptedException e) {
				if(msg != null){
					log.error("消息消息失败,param={} ,e = {}" , JSONObject.toJSONString(msg),e);
				}else{
					log.error("消息消息失败:" ,e);
				}
				Thread.currentThread().interrupt();
			}
		}
	}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值