第一步:定义一个线程池
package com.ucf.trade.util.common; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.springframework.stereotype.Component; /** * 线程池 * Description: * All Rights Reserved. * @version 1.0 2014年8月12日 下午3:57:16 */ @Component public class ThreadPool { //阻塞队列深度 private static int maxQueueSize; //核心线程数 private static int corePoolSize; //最大线程数 private static int maximumPoolSize; //线程池中的阻塞队列,请求数大于核心线程数时进阻塞队列等待 private static ArrayBlockingQueue<Runnable> queue; //线程池 private static ThreadPoolExecutor pool; static { maxQueueSize = Integer.parseInt(Constant.getValue(Constant.ThreadPoolQueueSize)); corePoolSize = Integer.parseInt(Constant.getValue(Constant.ThreadPoolSize)); maximumPoolSize = Integer.parseInt(Constant.getValue(Constant.ThreadPoolSize)); queue = new ArrayBlockingQueue<Runnable>(maxQueueSize); pool = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,3,TimeUnit.SECONDS,queue,new ThreadPoolExecutor.CallerRunsPolicy());//CallerRunsPolicy 超出线程池范围,立即开线程池外新线程处理,脱离线程池控制 } /** * 执行线程 * Description: * @Version1.0 2014年8月12日 下午3:56:08 by lianjing([email protected])创建 * @param task */ public void exec(Runnable task) { pool.execute(task); } /** * 判断阻塞队列满 * Description: * @Version1.0 2014年8月12日 下午3:56:29 by lianjing([email protected])创建 * @return */ public boolean isFull() { return getQueue().size() == maxQueueSize; } public ArrayBlockingQueue<Runnable> getQueue() { return queue; } public int getQueueSize() { return queue.size(); } }
package com.ucf.trade.util.common; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.stereotype.Component; @Component public class MyBeanFactory implements BeanFactoryAware { //spring工厂 private BeanFactory beanFactory ; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public Object getBean(String name) { return beanFactory.getBean(name); } public <T> T getBean(String name, Class<T> clazz) { return (T)beanFactory.getBean(name); } }
package com.ucf.trade.schedule; import java.util.List; import javax.annotation.Resource; import org.springframework.stereotype.Component; import com.ucf.platform.framework.core.log.UcfLogger; import com.ucf.platform.framework.core.log.UcfLoggerFactory; import com.ucf.trade.component.BatchPersistence; import com.ucf.trade.pojo.UcfBatchOrderDetail; import com.ucf.trade.util.common.Constant; import com.ucf.trade.util.common.MyBeanFactory; import com.ucf.trade.util.common.ThreadPool; @Component public class WithdrawBatchTask { private final static UcfLogger logger = UcfLoggerFactory.getLogger(WithdrawBatchTask.class); @Resource private MyBeanFactory myBeanFactory; @Resource private ThreadPool threadPool; @Resource private BatchPersistence batchPersistence; public void execTask() { logger.info("【批量代发-后台任务】开始扫描待处理订单。。。"); try { /* * 1.判断队列深度 */ if(threadPool.isFull()) { logger.info("【批量代发-后台任务】当前线程池阻塞队列深度已达到最大,暂停扫描,队列深度为:" + threadPool.getQueueSize()); try { Thread.sleep(10000); } catch (InterruptedException e) { logger.error(e.getMessage(), e); } } //2.扫描待处理记录 List<UcfBatchOrderDetail> detailList = batchPersistence.queryDetailListForWait(); int detailSize = detailList.size(); logger.info("【批量代发-后台任务】本次扫描待处理订单数量为:" + detailSize); //3.分配线程处理 for(UcfBatchOrderDetail detail : detailList) { BatchExecutor batchExecutor = myBeanFactory.getBean("batchExecutor",BatchExecutor.class); batchExecutor.setUcfBatchOrderDetail(detail); logger.info("【批量代发-后台任务】merchantNo:{},加入线程队列,等待执行。", detail.getMerchantNo()); threadPool.exec(batchExecutor); } /* * 4.持续扫描判断 * 本次没有记录,停顿5分钟 * 否则停顿时间为本次记录数除以最大线程数取整 + 1,单位秒 * 保证给每个线程留1秒处理时间 * 防止重复扫描到相同订单太多 */ if(detailSize == 0) { try { Thread.sleep(5 * 60 * 1000); } catch (InterruptedException e) { logger.error(e.getMessage(), e); } } else { int poolSize = Integer.parseInt(Constant.getValue(Constant.ThreadPoolSize)); int sleepTime = detailSize / poolSize + 1; try { Thread.sleep(sleepTime * 1000); } catch (InterruptedException e) { logger.error(e.getMessage(), e); } } } catch(Exception e) { logger.error(e.getMessage(), e); logger.info("【批量代发-后台任务】处理订单出现异常:{}", e.getMessage()); } logger.info("【批量代发-后台任务】本次扫描完成。"); } }
package com.ucf.trade.schedule; import java.util.Date; import java.util.List; import javax.annotation.Resource; import org.apache.commons.beanutils.BeanUtils; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import com.ucf.onlinepay.framework.common.util.StringUtil; import com.ucf.platform.framework.core.log.UcfLogger; import com.ucf.platform.framework.core.log.UcfLoggerFactory; import com.ucf.trade.component.BatchPersistence; import com.ucf.trade.dubbo.bo.WithdrawParamBo; import com.ucf.trade.dubbo.bo.WithdrawReturnBo; import com.ucf.trade.dubbo.service.WithdrawService; import com.ucf.trade.pojo.UcfBatchOrder; import com.ucf.trade.pojo.UcfBatchOrderDetail; import com.ucf.trade.util.common.TimeUtil; import com.ucf.trade.util.enums.TradeEnum; import com.ucf.trade.util.exception.ErrorCode; @Component @Scope("prototype") public class BatchExecutor implements Runnable { private final static UcfLogger logger = UcfLoggerFactory.getLogger(BatchExecutor.class); private UcfBatchOrderDetail ucfBatchOrderDetail; @Resource private BatchPersistence batchPersistence; @Resource private WithdrawService withdrawService; @Resource(name = "sharedTransactionTemplate") private TransactionTemplate transactionTemplate; // 手动提交事务 @Override public void run() { logger.info("【批量代发-后台任务】merchantNo:{},开始执行,调用单笔接口。", ucfBatchOrderDetail.getMerchantNo()); transactionTemplate.execute(new TransactionCallback<Object>() { @Override public Object doInTransaction(TransactionStatus status) { try { //1.锁批量明细表当前记录 UcfBatchOrderDetail lockDetail = new UcfBatchOrderDetail(); lockDetail = batchPersistence.queryOrderDetailAndLock(ucfBatchOrderDetail); if(lockDetail == null || lockDetail.getStatus().equals(TradeEnum.PRE_PAY_SUCCESS.getCode())) { return null; } //2.参数准备 WithdrawParamBo withdrawParamBo = new WithdrawParamBo(); BeanUtils.copyProperties(withdrawParamBo, ucfBatchOrderDetail); withdrawParamBo.setBankCardNo(ucfBatchOrderDetail.getAccountNo()); withdrawParamBo.setBankCardUserName(ucfBatchOrderDetail.getAccountName()); withdrawParamBo.setSubType(TradeEnum.TRANS_WITHDRAW_SUBTYPE_BATCH.getCode()); //获取noticeUrl UcfBatchOrder ucfBatchOrder = new UcfBatchOrder(); ucfBatchOrder.setBatchNo(ucfBatchOrderDetail.getBatchNo()); List<UcfBatchOrder> batchOrderList = batchPersistence.queryUcfBatchOrderByWhere(ucfBatchOrder); if(batchOrderList.size() > 0) { withdrawParamBo.setNoticeUrl(batchOrderList.get(0).getNoticeUrl()); } //3.调用单笔代发 WithdrawReturnBo withdrawReturnBo = withdrawService.withdraw(withdrawParamBo); //4.修改当前记录为已处理 UcfBatchOrderDetail updateCondition = new UcfBatchOrderDetail(); if(withdrawReturnBo.getResCode() != null && withdrawReturnBo.getResCode().equals(ErrorCode.OUT_ERROR_10005.getCode())) { updateCondition.setStatus(TradeEnum.FAIL.getCode()); updateCondition.setResCode(withdrawReturnBo.getResCode()); updateCondition.setResMessage(withdrawReturnBo.getResMessage()); } else if(withdrawReturnBo.getStatus().equals(TradeEnum.WAIT.getCode())) { updateCondition.setStatus(TradeEnum.PRE_PAY_SUCCESS.getCode()); } else { if(StringUtil.isEmpty(withdrawReturnBo.getStatus())) { updateCondition.setStatus(TradeEnum.FAIL.getCode()); updateCondition.setMessage(withdrawReturnBo.getResMessage()); updateCondition.setResCode(withdrawReturnBo.getResCode()); } else { if(withdrawReturnBo.getStatus().equals(TradeEnum.SUCCESS.getCode())){ updateCondition.setStatus(withdrawReturnBo.getStatus()); }else{ updateCondition.setStatus(withdrawReturnBo.getStatus()); updateCondition.setMessage(withdrawReturnBo.getResMessage()); updateCondition.setResCode(withdrawReturnBo.getResCode()); } } updateCondition.setMessage(withdrawReturnBo.getResMessage()); } updateCondition.setId(ucfBatchOrderDetail.getId()); if(!StringUtil.isEmpty(withdrawReturnBo.getTradeTime())) { updateCondition.setTradeTime(TimeUtil.getDateFromDATETIME14(withdrawReturnBo.getTradeTime())); } updateCondition.setGmtModify(new Date()); batchPersistence.updateUcfBatchOrderDetail(updateCondition); } catch(Exception e) { status.setRollbackOnly(); } return null; } }); } public UcfBatchOrderDetail getUcfBatchOrderDetail() { return ucfBatchOrderDetail; } public void setUcfBatchOrderDetail(UcfBatchOrderDetail ucfBatchOrderDetail) { this.ucfBatchOrderDetail = ucfBatchOrderDetail; } }
部分常量定义:
public class Constant { private final static UcfLogger logger = UcfLoggerFactory.getLogger(Constant.class); public static String ThreadPoolSize = "ThreadPoolSize"; public static String ThreadPoolQueueSize = "ThreadPoolQueueSize"; public static String PerMaxCount = "PerMaxCount";
}