task-DelayQueue-订单超时实例(task任务,DelayQueue阻塞队列)

5 篇文章 0 订阅
2 篇文章 0 订阅
很早就对task,queue有兴趣,今天总结一下,做个笔记。

一、对于多任务异步的项目中,task的作用很普遍,最近学习,和小试牛刀了一下,有一些感悟,做个笔记。
二、使用spring task,配置如下:

<bean id="orderTimeoutService"
        class="com.haohao.order.service.order.impl.OrderTimeoutServiceImpl"
        init-method="init" destroy-method="destroy">
        <property name="handlers">
            <map key-type="com.haohao.order.common.enums.TimeoutTypeEnum">
                <entry key="ORDER" value-ref="orderTimeoutHandler" />
                <entry key="REFUND" value-ref="refundTimeoutHandler" />
            </map>
        </property>
        <property name="loadTimeoutTask" value="${timeout.task.is.load}"/>
    </bean>

    <bean id="orderTimeoutHandler"
        class="com.haohao.order.service.timeout.handler.OrderTimeoutHandler">
        <property name="timeoutActions">
            <map>
                <entry key="wait_buyer_pay_deposit" value-ref="closeOrderAction" />
                <entry key="wait_buyer_pay_all" value-ref="closeOrderAction" />
                <entry key="wait_seller_send" value-ref="sellerSendGoodsAction" />
                <entry key="wait_buyer_receive" value-ref="receiveGoodsAction" />
            </map>
        </property>
    </bean>

    <bean id="refundTimeoutHandler"
        class="com.haohao.order.service.timeout.handler.RefundTimeoutHandler">
        <property name="timeoutActions">
            <map>
                <entry key="wait_seller_agree" value-ref="confirmRefundProtocolAction" />
                <entry key="wait_buyer_modify" value-ref="closeRefundAction" />
                <entry key="wait_buyer_send" value-ref="closeRefundAction" />
                <entry key="wait_seller_receive" value-ref="refundAction" />
                <entry key="wait_customer_service" value-ref="refundCustomerServiceAction" />
            </map>
        </property>
    </bean>

<task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="orderTimeoutService" method="loadRecentlyTimeoutInfo"   cron="${load.order.timeout.period}" />
</task:scheduled-tasks>

    <task:scheduler id="myScheduler" pool-size="5" />

Java代码:

/**
 * 
 */
package com.haohao.order.service.order.impl;

import java.util.List;
import java.util.Map;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.haohao.order.common.enums.TimeoutTypeEnum;
import com.haohao.order.common.util.BeanUtils;
import com.haohao.order.dal.timeout.OrderTimeoutInfoDAO;
import com.haohao.order.dal.timeout.OrderTimeoutInfoDO;
import com.haohao.order.service.order.OrderTimeoutService;
import com.haohao.order.service.timeout.handler.TimeoutHandler;
import com.haohao.order.service.timeout.model.TimeoutModel;

/**
 * 功能描述:
 * 
 * @author mandy.hu
 */

public class OrderTimeoutServiceImpl implements OrderTimeoutService {
    private static final Logger logger = LoggerFactory.getLogger(OrderTimeoutServiceImpl.class);

    @Resource
    private OrderTimeoutInfoDAO orderTimeoutInfoDAO;

    private DelayQueue<TimeoutModel> timeoutQueue;
    @Autowired(required = false)
    private ExecutorService executorService;
    private Map<TimeoutTypeEnum, TimeoutHandler> handlers;
    private transient boolean running;

    private boolean isLoadTimeoutTask;

    protected void init() {
        if(isLoadTimeoutTask) {
            logger.info("初始化超时队列");
            running = true;
            //初始化一个阻塞队列
            timeoutQueue = new DelayQueue<TimeoutModel>();

            startHandler();
        }
    }
    //这个方法就是用来处理业务的,意思是查询超时的订单,并放在DelayQueue中。
    @Override
    public void loadRecentlyTimeoutInfo() {
        if(isLoadTimeoutTask) {
            logger.info("加载即将超时的信息...");

            List<OrderTimeoutInfoDO> orderTimeoutInfoDOs = orderTimeoutInfoDAO.queryRecentlyOrderTimeoutInfos();

            logger.info("加载即将超时的信息...loadRecentlyTimeoutInfo  orderTimeoutInfoDOs:{}",orderTimeoutInfoDOs);

            List<TimeoutModel> timeoutModels = BeanUtils.convertList(orderTimeoutInfoDOs, TimeoutModel.class);

            if (CollectionUtils.isNotEmpty(timeoutModels)) {
                timeoutQueue.addAll(timeoutModels);
            }
            logger.info("加载即将超时的信息...loadRecentlyTimeoutInfo timeoutQueue:{}",timeoutQueue);
        }
    }

    @PreDestroy
    protected void destroy() {
        running = false;
    }

    private void startHandler() {
        logger.info("启动超时监听线程");

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (running) {
                    try {
                    //阻塞队列执行take()方法,删除队列顶部的一个对象,并返回删除的对象。这个方法是阻塞方法,如果队列中没有对象,这个线程将被阻塞,知道队列中有对象。
                        TimeoutModel timeoutModel = timeoutQueue.take();
//对象交给ExecutorService处理,ExecutorService是一个异步处理机制,相当于一个线程池,意思就把这个take()的对象委托给ExecutorService处理。
                        getExecutorService().execute(new TimeoutHandlerTask(timeoutModel));
                    } catch (InterruptedException e) {
                        logger.warn("处理超时失败", e);
                        e.printStackTrace();
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    class TimeoutHandlerTask implements Runnable {
        private TimeoutModel timeoutModel;

        public TimeoutHandlerTask(TimeoutModel timeoutModel) {
            this.timeoutModel = timeoutModel;
        }

        @Override
        public void run() {
            TimeoutHandler handler = handlers.get(timeoutModel.getTimeoutType());

            if (handler != null) {
                handler.onTimeout(timeoutModel);
            }
        }

    }

    public ExecutorService getExecutorService() {
        if (executorService == null) {
        //得到executorService 对象,其中Runtime.getRuntime()相当于new一个对象,、、Executors.newFixedThreadPool(xxx)最大执行多少个线程的executorService 。
            executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
        }

        return executorService;
    }

    public void setExecutorService(ExecutorService executorService) {
        this.executorService = executorService;
    }

    public Map<TimeoutTypeEnum, TimeoutHandler> getHandlers() {
        return handlers;
    }

    public void setHandlers(Map<TimeoutTypeEnum, TimeoutHandler> handlers) {
        this.handlers = handlers;
    }

    public void setLoadTimeoutTask(boolean isLoadTimeoutTask) {
        this.isLoadTimeoutTask = isLoadTimeoutTask;
    }

}

三:上面注释已经很清楚了,为了防止以后不认识自己写注释,在这里再系统的说一下流程。

  1. 在spring配置文件中,配置task。
<task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="orderTimeoutService" method="loadRecentlyTimeoutInfo"  cron="${load.order.timeout.period}" />
    </task:scheduled-tasks>

<task:scheduler id="myScheduler" pool-size="5" />

其中ref=”orderTimeoutService”是要执行的类,method=”loadRecentlyTimeoutInfo”是要执行这个类中的方法,cron=”${load.order.timeout.period}” 是执行规则多长时间执行,什么周期执行,都可以灵活设置。

  1. 配置执行的类:
<bean id="orderTimeoutService"
        class="com.haohao.order.service.order.impl.OrderTimeoutServiceImpl"
        init-method="init" destroy-method="destroy">
        <property name="handlers">
            <map key-type="com.haohao.order.common.enums.TimeoutTypeEnum">
                <entry key="ORDER" value-ref="orderTimeoutHandler" />
                <entry key="REFUND" value-ref="refundTimeoutHandler" />
            </map>
        </property>
        <property name="loadTimeoutTask" value="${timeout.task.is.load}"/>
    </bean>

    <bean id="orderTimeoutHandler"
        class="com.haohao.order.service.timeout.handler.OrderTimeoutHandler">
        <property name="timeoutActions">
            <map>
                <entry key="wait_buyer_pay_deposit" value-ref="closeOrderAction" />
                <entry key="wait_buyer_pay_all" value-ref="closeOrderAction" />
                <entry key="wait_seller_send" value-ref="sellerSendGoodsAction" />
                <entry key="wait_buyer_receive" value-ref="receiveGoodsAction" />
            </map>
        </property>
    </bean>

    <bean id="refundTimeoutHandler"
        class="com.haohao.order.service.timeout.handler.RefundTimeoutHandler">
        <property name="timeoutActions">
            <map>
                <entry key="wait_seller_agree" value-ref="confirmRefundProtocolAction" />
                <entry key="wait_buyer_modify" value-ref="closeRefundAction" />
                <entry key="wait_buyer_send" value-ref="closeRefundAction" />
                <entry key="wait_seller_receive" value-ref="refundAction" />
                <entry key="wait_customer_service" value-ref="refundCustomerServiceAction" />
            </map>
        </property>
    </bean>

OrderTimeoutServiceImpl类中有两个方法init-method=”init” destroy-method=”destroy”,一个是这个类加载时就会执行的,另一个是这个类销毁时执行的,init-method方法做一些初始化操作。在这个类中有一个属性,是一个map,名字是handlers,handlers中有初始化了两个对象,本文重点不是这里,就不多赘述了

  1. 看看这一个类的具体实现,首先是初始化方法。
protected void init() {
        if(isLoadTimeoutTask) {
            logger.info("初始化超时队列");
            running = true;
            timeoutQueue = new DelayQueue<TimeoutModel>();

            startHandler();
        }
    }

这个方法很简单就是new一个阻塞队列DelayQueue。之后执行startHandler()方法,

private void startHandler() {
        logger.info("启动超时监听线程");

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (running) {
                    try {
                        TimeoutModel timeoutModel = timeoutQueue.take();

                        getExecutorService().execute(new TimeoutHandlerTask(timeoutModel));
                    } catch (InterruptedException e) {
                        logger.warn("处理超时失败", e);
                        e.printStackTrace();
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

这个方法目的是开起监听,利用的是DelayQueue阻塞队列的特性,方法中调用take()方法,这个方法是阻塞的方法,意思是移除队列中顶部的对象,并返回这个对象,如果队列是空,就会一直等待,等待队列中有对象,线程也处于阻塞的状态,同事就起到了监听的作用。getExecutorService().execute(new TimeoutHandlerTask(timeoutModel))这个方法是把timeoutModel 对象委托给ExecutorService()处理,这边好处理下一个任务。

public ExecutorService getExecutorService() {
        if (executorService == null) {
            executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
        }

        return executorService;
    }

这个就是得到ExecutorService对象, ExecutorService是一个异步处理机制,Executors.newFixedThreadPool(Num);最大能处理Num个线程的ExecutorService。调用ExecutorService的execute()方法就是委托了。

public void loadRecentlyTimeoutInfo() {
        if(isLoadTimeoutTask) {
            logger.info("加载即将超时的信息...");

            List<OrderTimeoutInfoDO> orderTimeoutInfoDOs = orderTimeoutInfoDAO.queryRecentlyOrderTimeoutInfos();

            logger.info("加载即将超时的信息...loadRecentlyTimeoutInfo  orderTimeoutInfoDOs:{}",orderTimeoutInfoDOs);

            List<TimeoutModel> timeoutModels = BeanUtils.convertList(orderTimeoutInfoDOs, TimeoutModel.class);

            if (CollectionUtils.isNotEmpty(timeoutModels)) {
                timeoutQueue.addAll(timeoutModels);
            }
            logger.info("加载即将超时的信息...loadRecentlyTimeoutInfo timeoutQueue:{}",timeoutQueue);
        }
    }

这个方法就是在spring task中配置要执行的方法,刚开始的时候一直在想在哪里有数据放在了DelayQueue中,就是这里,将想要监听的数据放在DelayQueue中,在startHandler()方法中就能监听到,这是task就是一个闭环了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值