应用场景:
1、订单成功后,在30分钟内没有支付,自动取消订单
2、外卖平台发送订餐通知,下单成功后60s给用户推送短信
3、如果订单一直处于某一个未完结状态时,及时处理关单,并退还库存
实现思路:
具体代码:
// 初始定时任务线程池
@Componentpublic class ScheduledExecutor {
private static final Logger logger = LoggerFactory.getLogger(ScheduledExecutor.class);
private ScheduledThreadPoolExecutor executor;
public void execute(Runnable runnable, long delay) {
executor.schedule(runnable, delay, TimeUnit.MILLISECONDS);
}
@PostConstruct
public void init() {
// 初始化线程池
executor = new ScheduledThreadPoolExecutor(10);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
}
@PreDestroy
public void destroy() {
executor.shutdown();
logger.info("ServerExecutor-destroy():threadExecutor:销毁");
}
}
// 任务执行线程池
@Component
public class ScheduledExecutor {
private static final Logger logger = LoggerFactory.getLogger(ScheduledExecutor.class);
private ScheduledThreadPoolExecutor executor;
public void execute(Runnable runnable, long delay) {
executor.schedule(runnable, delay, TimeUnit.MILLISECONDS);
}
@PostConstruct
public void init() {
// 初始化线程池
executor = new ScheduledThreadPoolExecutor(10);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
}
@PreDestroy
public void destroy() {
executor.shutdown();
logger.info("ServerExecutor-destroy():threadExecutor:销毁");
}
}
// service
@Slf4j
@Component
public class RedisServiceTest{
@Autowiredprivate RedisUtil redisUtil;
@Autowiredprivate ScheduledExecutor schedule;
@Autowiredprivate CachedExecutor cachedExecutor;
private static AtomicBoolean exists = new AtomicBoolean(true);
@PostConstruct
public void init() {
try {
cachedExecutor.executeTask(() -> {
// 1:初始化从redis中获取到最近待待失效订单
log.debug("开始初始化============");
TypedTuple<Object> tupleSet = popOrder();
// 2:scheduleTask delay execute该订单
executeTask(tupleSet);
});
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
@PreDestroy
public void destroy() {
exists.set(false);
}
/**
* 实例 scheduled
*
* @param tupleSet
*/
public void executeTask(TypedTuple<Object> tupleSet) {
if (null != tupleSet) {
Long expireTime = Double.valueOf(tupleSet.getScore()).longValue();
long delayTime = expireTime - System.currentTimeMillis();
// 实例taskTrack
schedule.execute(() -> {
TypedTuple<Object> tuple = popOrder();
executeTask(tuple);
}, delayTime);
}
}
/**
* 1:尝试消费 2:实例新的scheduled
*
* @return
*/
public TypedTuple<Object> popOrder() {
TypedTuple<Object> tupleSet = null;
//
while (exists.get()) {
// 获取队列头数据
tupleSet = redisUtil.zrangeWithScore("Test:Order:ToPay");
if (null == tupleSet) {
try {
Thread.sleep(2000);
continue;
} catch (Exception e) {
log.error("{}", e);
}
}
Long expireTimeLong = Double.valueOf(tupleSet.getScore()).longValue();
if (System.currentTimeMillis() >= expireTimeLong) {
String orderId = tupleSet.getValue().toString();
// TODO 处理过期数据 然后移除队列 这里要注意 多节点处理数据时 不安全问题 利用redis单线程 删除成功方可操作订单
} else {
// 如果存在待失效则弹出
log.debug("存在待失效============");
break;
}
}
return tupleSet;
}
}