原创 不码不疯魔 不码不疯魔 2023-08-26 12:12 发表于四川

收录于合集

#延迟队列1个

#基于JDK实现延迟队列1个

#取消订单1个

#高频面试题7个

20

23

不疯魔不成活,大家好呀,我是科哥,江湖ID 不码不疯魔

图片

大家好!今天我们将一起探讨一个高级Java技术话题——基于JDK实现延迟队列。这个主题对于许多企业级应用来说都非常重要,因为它可以帮助我们解决一些具有挑战性的业务问题。

在现实生活中,很多场景都需要用到延迟队列。以下就是使用基于JDK的延迟队列的企业级实战场景的三个例子:

1) 订单处理系统:在电商或物流公司中,订单的生成和处理是核心业务之一。当一个订单生成后,我们需要尽快处理该订单,但同时我们也需要等待一些必要的操作完成,比如支付确认、库存更新等。我们可以使用延迟队列来实现这个流程:当订单生成时,我们将订单信息添加到延迟队列中,并设定一定的延迟时间,比如支付确认后的时间点。当延迟期满时,后台处理程序会自动从队列中取出该订单进行后续处理。

2) 消息推送系统:在社交或在线聊天应用中,消息的推送需要及时且准确。但是,某些情况下,我们可能需要延迟一段时间再发送消息,比如在用户注册后的一段时间内发送欢迎消息。我们可以使用延迟队列来实现这个功能:当用户注册时,将发送欢迎消息的请求添加到延迟队列中,并设定一定的延迟时间,比如注册后的24小时。当延迟期满时,后台处理程序会自动从队列中取出该请求,并发送欢迎消息给用户。

3) 定时任务调度:在企业级应用中,我们可能需要定时执行某些任务,比如每天固定时间点进行数据统计、清空临时文件等。我们可以使用延迟队列来实现这个功能:当任务需要执行时,将任务请求添加到延迟队列中,并设定一定的延迟时间,比如每天的固定时间点。当延迟期满时,后台处理程序会自动从队列中取出该请求,并执行相应的任务。

图片

企业实战案例

假设我们正在开发一个电商网站,用户可以在该网站上购买商品。为了提供更好的用户体验,我们希望在用户下单后,能够立即返回订单信息,而不是让用户等待一段时间。但是,我们还需要确保订单能够按时结算,例如在订单生成后的10分钟内进行结算。这时,我们就可以使用基于JDK的延迟队列来解决这个问题。

在用户下单时,我们可以将订单信息放入延迟队列中,并设定10分钟的时间间隔。当时间间隔到达后,后台线程可以从队列中取出该订单信息,并进行结算操作。这样,用户可以立即得到订单信息,同时我们也能保证订单能够按时结算。

为了满足这个需求,我们需要实现一个基于JDK的延迟队列。这个队列应该具有以下特性:

延迟性:我们可以在队列的元素被取出之前,给它们设定一个时间,到了这个时间点,元素才会被取出。

可靠性:队列中的元素不能丢失,必须保证它们能被正确地存入和取出

高并发:在多线程环境下,队列的操作必须保证线程安全。

由于篇幅和格式的限制,我无法在这里提供完整的代码。但我可以为您提供部分代码的示例,以展示如何实现基于JDK的延迟队列。

@Override
public RespResult<String> createOrder(OrderSaveDTO orderSaveDTO) {
    OrderInfo orderInfo = new OrderInfo();
    orderInfo.setId(String.valueOf(DCGenIdUtil.genIdBySnowflake()));
    orderInfo.setOrderTime(new Date());
    String orderNo = GenerateSequenceUtil.generateSequenceNo();
    if (!StringUtils.isEmpty(orderNo)){
        orderInfo.setOrderNo(orderNo);
    }
    orderInfo.setStatus(Constant.ORDER_CREATE);
    //拷贝对象(只拷贝不为空的属性)
    DCBeanUtil.copyNotNull(orderInfo, orderSaveDTO);
    //保存订单
    orderMapper.saveOrderInfo(orderInfo);
    // 添加延时支付取消订单任务
    JDKDelayQueue.addDelayTaskWithSeconds(orderInfo, 2, PayOrderCancelWithJDKListener.class);
    return RespResult.success(orderInfo.getOrderNo());
}

/**
 * 基于jdk DelayQueue初始化队列监听
 */
@Slf4j
@Component
public class JDKDelayedQueueInit implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        startThread(applicationContext.getBeansOfType(JDKDelayedQueueListener.class));
    }

    /**
     * 启动线程获取队列
     * @param map     任务回调监听
     */
    private <T> void startThread(Map<String, JDKDelayedQueueListener> map) {
        //由于此线程需要常驻,可以新建线程,不用交给线程池管理
        Thread thread = new Thread(() -> {
            log.info("启动监听JDK延时队列线程!!!");
            while (true) {
                for (Map.Entry<String, JDKDelayedQueueListener> taskEventListenerEntry : map.entrySet()) {
                    String queueName = taskEventListenerEntry.getValue().getClass().getSimpleName();
                    try {
                        JDKDelayTask<T> jdkDelayTask = JDKDelayQueue.delayQueue.poll();
                        if(ObjectUtil.isNull(jdkDelayTask)){
                            try{
                                // 睡眠一下,防止竞争太激烈, 对CPU产生影响
                                Thread.sleep(1000);
                            }catch (Exception e){
                                log.error(e.getMessage(),e);
                            }
                            continue;
                        }
                        T t = jdkDelayTask.getBody();
                        if(t == null){
                            continue;
                        }
                        // 重新设置traceId
                        TraceHelper.getCurrentTrace();
                        long start = System.currentTimeMillis();
                        log.info("开始执行业务逻辑,queueName:{},data:{}",queueName,JSONUtil.toJsonStr(t));
                        taskEventListenerEntry.getValue().execute(t);
                        log.info("执行业务逻辑结束, 总耗时:{}ms", System.currentTimeMillis() - start);
                    } catch (Exception e) {
                        log.error("启动监听JDK延时队列线程系统异常! errMsg:{}", e.getMessage() ,e);
                    }
                }
            }
        });
        thread.setName("jdk-delayqueue");
        thread.setDaemon(true);
        thread.start();
    }
}

图片

图片

点击下方公众号进入关注,后台回复【JDK延迟队列】即可获取如上图所有源码,大量的商用级方案已经更新,记得关注,免费领取,标记星号哟!!!

Logo

欢迎大家加入成都城市开发者社区,“和我在成都的街头走一走”,让我们一起携手,汇聚IT技术潮流,共建社区文明生态!

更多推荐