java订单超时取消设计_商城系统 - 自动取消超时订单解决方案

目的

当订单超过指定时间(毫秒),未支付时,系统自动取消订单。

方案

初步方案

1、定时从数据库获取待取消订单, 放入集合中。

2、将剩余10分钟内待取消订单创建线程,加入(缓存)线程池中,休眠(取消时间-当前时间)后执行取消任务。

3、任务执行完成后移除任务。

缺点:未限制线程数量。如果某个时间段退款过多,会导致创建过多线程。

优化方案1

1、将上述方案缓存线程池,修改为定长线程池。

缺点:运行线程占满时,会导致后续新增的取消订单(退款时间小于休眠中的订单),无法按照指定时间执行。

原因:例如线程池中,可同时执行的线程数为2。当前线程池中,已有两个待取消订单在执行队列中(休眠了执行时间后执行)。导致新增的取消订单任务,需等待前两个中的某一个,执行完成后,才能执行新增的取消订单任务。

最终方案 (如有其他方案、此方案有待改进的地方,欢迎评论一起探讨)

1、定时从数据库获取待取消订单, 放入集合中。将集合按照取消时间,从小到大排序。并通知步骤2。

2、获取集合中,第一个任务的订单取消时间,wait(订单取消时间-当前时间)后将线程将线程加入线程池中,执行取消订单任务。无任务时wait()。

3、任务执行完成后移除任务。

简易流程图.png

实现代码 (待删除无用代码)

package com.gtmc.uccs.common.util;

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.Collections;

import java.util.Date;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import lombok.extern.slf4j.Slf4j;

/**

* 定时处理工具类

*

* @description: 定时处理工具类

* @author: chenfei

* @create: 2020-12-23 16:21:55

*/

@Slf4j

public abstract class TimingProcess {

/**

* 执行任务的线程池

*/

private final ExecutorService taskExecuteThreadPool;

/**

* 待执行的任务队列

*/

private final List> taskQueue = Collections.synchronizedList(new LinkedList>());

/**

* 执行中的任务队列

*/

private final List> readiedTaskQueue = Collections.synchronizedList(new LinkedList>());

/**

* 调度程序占用的线程数

*/

private final int processTread = 2;

/**

* 循环调用间隔

*/

private int sleepTime;

private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

/**

* 创建定时处理程序 立即执行当前可执行方法 并在指定时间循环调用

*

* @param sleepTime 循环调用间隔时间 单位:分

* @author: chenfei

* @create: 2020-12-24 13:19:01

*/

public TimingProcess(int sleepTime) {

this(sleepTime, 5);

}

/**

* 创建定时处理程序 立即执行当前可执行方法 并在指定时间循环调用

*

* @param sleepTime 循环调用间隔时间 单位:分

* @author: chenfei

* @create: 2020-12-24 13:19:01

*/

public TimingProcess(int sleepTime, int maxTaskExecuteNum) {

this.sleepTime = sleepTime;

taskExecuteThreadPool = Executors.newFixedThreadPool(maxTaskExecuteNum+processTread);

this.executeTask();

createThreadRunDispatchTask(sleepTime);

}

/**

* 创建一个线程 根据循环调用调度任务

*

* @description: 根据指定时间循环调用调度任务

* @param sleepTime 间隔多长时间循环调用

* @author: chenfei

* @create: 2020-12-24 12:50:22

*/

private void createThreadRunDispatchTask(int sleepTime) {

taskExecuteThreadPool.execute((new Runnable() {

@Override

public void run() {

while(true) {

dispatchTaskNow();

try {

Thread.sleep(sleepTime*60*1000);

} catch (InterruptedException e) {

log.error("休眠被异常打断", e);

}

}

}

}));

}

/**

* 执行调用任务 循环扫描队列 将可执行任务创建线程进行定时处理

*

* @description: 执行调用任务 循环扫描队列 将可执行任务创建线程进行定时处理

* @author: chenfei

* @create: 2020-12-24 13:01:44

*/

private synchronized void dispatchTaskNow() {

this.sortTaskQueue();

log.debug("任务调度 开始执行 ... 当前队列等待执行任务: {}个 预备中的任务: {}", this.taskQueue.size(), readiedTaskQueue.size());

Iterator> iterator = this.taskQueue.iterator();

while(iterator.hasNext()) {

Task task = iterator.next();

Date taskRunTime = task.getTaskRunTime();

// 如果执行日期小于定时循环时间 创建任务并加入到执行中的队列

Calendar calendar = Calendar.getInstance();

calendar.add(Calendar.MINUTE, sleepTime);

if(calendar.getTime().compareTo(taskRunTime) >= 0) {

readiedTaskQueue.add(task);

synchronized (readiedTaskQueue) {

readiedTaskQueue.notify();

}

}

}

this.taskQueue.removeAll(readiedTaskQueue);

log.debug("任务调度 执行结束 ... 当前队列等待执行任务: {}个 预备中的任务: {}", this.taskQueue.size(), readiedTaskQueue.size());

}

/**

* 执行任务

*
1)当前预备队列中有可执行任务时,取时间最小的作为等待时间,等待时间结束时开始处理任务。

*
2) 当前预备队列无可执行任务时,一直等待直至被唤醒

*

*

* @description: 执行任务

* @author: chenfei

* @create: 2020-12-24 23:38:57

*/

private void executeTask() {

Thread thread = new Thread(new Runnable() {

@Override

public void run() {

while(true) {

synchronized (readiedTaskQueue) {

// 排序预备中的任务

Collections.sort(readiedTaskQueue);

try {

if(readiedTaskQueue.size()<=0) {

readiedTaskQueue.wait();

}

Task task = readiedTaskQueue.get(0);

Date taskRunTime = task.getTaskRunTime();

// 第一次判断需要睡眠多久

long sleepTime = taskRunTime.getTime()-System.currentTimeMillis();

if(sleepTime>0) {

readiedTaskQueue.wait(sleepTime);

}

// 第二次获取时间 判断当前是否可执行人 有可能是被调度器唤醒 非等待时间结束

sleepTime = taskRunTime.getTime()-System.currentTimeMillis();

if(sleepTime<=0) {

taskExecuteThreadPool.execute(taskToThread(task));

readiedTaskQueue.remove(task);

}

} catch (InterruptedException e) {

log.error("线程等待被异常唤醒", e);

}

}

}

}

});

taskExecuteThreadPool.execute(thread);

}

/**

* 创建一个线程执行任务内容

*

* @description: 创建一个线程执行任务内容

* @param t

* @param date 定时处理的时间

* @return

* @author: chenfei

* @create: 2020-12-24 13:02:45

*/

private Runnable taskToThread(final Task task) {

return new Runnable() {

@Override

public void run() {

try {

log.debug("任务定时执行时间: {} 当前系统时间: {}",SIMPLE_DATE_FORMAT.format(task.getTaskRunTime()), SIMPLE_DATE_FORMAT.format(new Date()));

handle(task);

}finally {

log.debug("{} 任务执行结束 即将从队列中移除", task);

readiedTaskQueue.remove(task);

}

}

};

}

/**

* 任务执行的内容

*

* @description: 需执行的任务

*

* @param task 任务

* @author: chenfei

* @create: 2020-12-23 17:34:19

*/

public abstract void handle(Task task);

/**

* 添加一个任务到队列 当前有可执行任务时,会立即进入执行队列。 其余进去待调度队列

* @description: 添加一个任务到队列

* @param task 任务

* @author: chenfei

* @create: 2020-12-24 21:26:36

*/

public void addTask(Task task) {

if(task == null) {

return;

}

synchronized (this) {

if(readiedTaskQueue.contains(task) || taskQueue.contains(task)) {

return;

}

taskQueue.add(task);

}

dispatchTaskNow();

}

/**

* 添加全部任务

*

* @description: 添加全部任务

* @param tasks 任务集合

* @author: chenfei

* @create: 2020-12-24 15:36:02

*/

public void addAllTask(List> tasks) {

if(tasks == null) {

return;

}

synchronized (this) {

for (Task task : tasks) {

if(readiedTaskQueue.contains(task) || taskQueue.contains(task)) {

return;

}

taskQueue.add(task);

}

this.sortTaskQueue();

}

dispatchTaskNow();

}

private void sortTaskQueue() {

Collections.sort(this.taskQueue);

}

/**

* 任务类

*

* @program: common-core

* @description: 任务类

* @author: chenfei

* @create: 2020-12-24 21:53:58

*/

public static class Task implements Comparable>{

/**

* 执行任务所需的参数对象

*/

private T taskParam;

/**

* 任务运行时间

*/

private Date taskRunTime;

public Task(T taskParam, Date taskRunTime) {

super();

this.taskParam = taskParam;

this.taskRunTime = taskRunTime;

}

public T getTaskParam() {

return taskParam;

}

public void setTaskParam(T taskParam) {

this.taskParam = taskParam;

}

public Date getTaskRunTime() {

return taskRunTime;

}

@Override

public int compareTo(Task task) {

return this.getTaskRunTime().compareTo(task.getTaskRunTime());

}

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + ((taskParam == null) ? 0 : taskParam.hashCode());

result = prime * result + ((taskRunTime == null) ? 0 : taskRunTime.hashCode());

return result;

}

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

@SuppressWarnings("unchecked")

Task other = (Task) obj;

if (taskParam == null) {

if (other.taskParam != null)

return false;

} else if (!taskParam.equals(other.taskParam))

return false;

if (taskRunTime == null) {

if (other.taskRunTime != null)

return false;

} else if (!taskRunTime.equals(other.taskRunTime))

return false;

return true;

}

}

}

你可能感兴趣的:(java订单超时取消设计)