功能实现:延迟一段时间再执行一个操作
参考文章:https://www.cnblogs.com/barrywxx/p/8525907.html
1. DelayOrderQueueManager
package cn.zykj.delqueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 延时队列管理类,用来添加任务、执行任务
*
*/
public class DelayOrderQueueManager {
private final static int DEFAULT_THREAD_NUM = 5;
private static int thread_num = DEFAULT_THREAD_NUM;
// 固定大小线程池
private ExecutorService executor;
// 守护线程
private Thread daemonThread;
// 延时队列
private DelayQueue<DelayOrderTask<?>> delayQueue;
// private static final AtomicLong atomic = new AtomicLong(0);
// private final long n = 1;
private static DelayOrderQueueManager instance = new DelayOrderQueueManager();
private DelayOrderQueueManager() {
executor = Executors.newFixedThreadPool(thread_num);
delayQueue = new DelayQueue<>();
init();
}
public static DelayOrderQueueManager getInstance() {
return instance;
}
/**
* 初始化
*/
public void init() {
daemonThread = new Thread(execute());
daemonThread.setName("DelayQueueMonitor");
daemonThread.start();
}
private Runnable execute() {
Runnable run = new Runnable() {
@Override
public void run() {
while (true) {
// Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
// System.out.println("当前存活线程数量:" + map.size());
// int taskNum = delayQueue.size();
// System.out.println("当前延时任务数量:" + taskNum);
try {
// 从延时队列中获取任务
DelayOrderTask<?> delayOrderTask = delayQueue.take();
if (delayOrderTask != null) {
Runnable task = delayOrderTask.getTask();
if (null == task) {
continue;
}
// 提交到线程池执行task
executor.execute(task);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
return run;
}
/**
* 添加任务
*
* @param task
* @param time
* 延时时间
* @param unit
* 时间单位
*/
public void put(Runnable task, long time, TimeUnit unit) {
// 获取延时时间
long timeout = TimeUnit.NANOSECONDS.convert(time, unit);
// 将任务封装成实现Delayed接口的消息体
DelayOrderTask<?> delayOrder = new DelayOrderTask<>(timeout, task);
// 将消息体放到延时队列中
delayQueue.put(delayOrder);
}
/**
* 删除任务
*
* @param task
* @return
*/
public boolean removeTask(DelayOrderTask task) {
return delayQueue.remove(task);
}
}
2. DelayOrderTask
package cn.zykj.delqueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* 延时队列中的消息体将任务封装为消息体
*
*/
public class DelayOrderTask<T extends Runnable> implements Delayed {
private final long time;
private final T task; // 任务类,也就是之前定义的任务类
/**
* @param timeout
* 超时时间(秒)
* @param task
* 任务
*/
public DelayOrderTask(long timeout, T task) {
this.time = System.nanoTime() + timeout;
this.task = task;
}
@Override
public int compareTo(Delayed o) {
DelayOrderTask other = (DelayOrderTask) o;
long diff = time - other.time;
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
} else {
return 0;
}
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(this.time - System.nanoTime(), TimeUnit.NANOSECONDS);
}
@Override
public int hashCode() {
return task.hashCode();
}
public T getTask() {
return task;
}
}
3. DelayOrderWorker(逻辑处理类)
spring 框架中如果需要调用 service、mapper 层则需手动 getBean 或当成参数传递进来,才可正常使用,否则报空指针异常
package cn.zykj.delqueue;
import java.math.BigDecimal;
import cn.zykj.dao.TransactionrecordMapper;
import cn.zykj.dao.WallettableMapper;
import cn.zykj.service.impl.WallettableServiceImpl;
/**
* 延时执行队列(平台内延时到账)
*
*/
public class DelayOrderWorker implements Runnable {
// 变量根据需求定义
public int memberid = 0;
public String virtualcurrencyname = "";
public String sourceaddress = "";
public BigDecimal transactionnumber = BigDecimal.ZERO;
public int transactionfundstype = 0;
private WallettableServiceImpl wallettableServiceImpl;
private WallettableMapper wallettableMapper;
private TransactionrecordMapper transactionrecordMapper;
/**
* 创建延时任务 (构造函数参数根据自己需求创建)
* spring中使用service或mapper时手动getBean或传递进来
* @param memberid 会员ID
* @param virtualcurrencyname 币种类型
* @param sourceaddress 来源地址
* @param transactionnumber 交易数量
* @param transactionfundstype 交易资金类型
*/
public DelayOrderWorker(int memberid, String virtualcurrencyname, String sourceaddress,
BigDecimal transactionnumber, int transactionfundstype,
WallettableServiceImpl wallettableServiceImpl, WallettableMapper wallettableMapper, TransactionrecordMapper transactionrecordMapper){
System.out.println("<----------平台内转账处理中>目标=》会员ID="+memberid+">币种类型="+virtualcurrencyname
+">来源="+sourceaddress+">数量="+transactionnumber+">资金类型="+transactionfundstype+"---------->");
this.memberid = memberid;
this.virtualcurrencyname = virtualcurrencyname;
this.sourceaddress = sourceaddress;
this.transactionnumber = transactionnumber;
this.transactionfundstype = transactionfundstype;
this.wallettableServiceImpl = wallettableServiceImpl;
this.wallettableMapper = wallettableMapper;
this.transactionrecordMapper = transactionrecordMapper;
}
@Override
public void run() {
// 逻辑处理
wallettableServiceImpl.app_transfer_in(memberid, virtualcurrencyname, sourceaddress, transactionnumber, transactionfundstype, wallettableMapper, transactionrecordMapper);
}
}
使用方法: