使用延時隊列DelayQueue實現訂單超時自動關閉
DelayQueue 是一個線程安全的隊列。可以實現異步操作
首先創建一個訂單實體類
@Getter
@Setter
public class OrderInfo implements Serializable , Delayed
{
private static final long serialVersionUID = 1L;
private String orderNo;// 訂單號
private Integer status;// 訂單狀態
private String expTime;// 訂單過期時間
private String createTime;//訂單創建時間
/**
* 用於延時隊列內部比較排序:當前訂單的過期時間 與 隊列中對象的過期時間 比較
*/
@Override
public int compareTo(Delayed o) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long nowThreadtime = 0;
long queueThreadtime = 0;
try {
nowThreadtime = formatter.parse(this.expTime).getTime();
queueThreadtime = formatter.parse(((OrderInfo)o).expTime).getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return Long.valueOf(nowThreadtime).compareTo(Long.valueOf(queueThreadtime));
}
/**
* 時間單位:秒
* 延遲關閉時間 = 過期時間 - 當前時間
*/
@Override
public long getDelay(TimeUnit unit) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long time = 0;
try {
time = formatter.parse(this.expTime).getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return time - System.currentTimeMillis();
}
}
下面實現隊列移除超市訂單
/**
* [使用延時隊列DelayQueue實現訂單超時關閉]
* [後臺守護線程不斷的執行檢測工作]
* [雙檢查模式實現單例模式]
*/
@Component
public class OrderOverTimeClose
{
private volatile static OrderOverTimeClose oderOverTimeClose = null;
//我這裏是一個商品訂單實體類
private GoodsOrderRepository goodsOrderRepository;
private OrderOverTimeClose() {
this.goodsOrderRepository = ApplicationContextProvider.getBean(GoodsOrderRepository.class);
}
/**
* 單例模式,雙檢查鎖模式,在併發環境下對象只被初始化一次
*/
public static OrderOverTimeClose getInstance(){
if(oderOverTimeClose == null ){
synchronized(OrderOverTimeClose.class){
oderOverTimeClose = new OrderOverTimeClose();
}
}
return oderOverTimeClose;
}
/**
* 守護線程
*/
private Thread mainThread;
/**
* 啓動方法
*/
public void init(){
/**初始化時加載數據庫中需處理超時的訂單**/
//循環訂單 獲取狀態 調用orderPutQueue();
// 創建初始訂單
long createTime = System.currentTimeMillis();
String currentTime = OrderPay.getTime(createTime);
String overTime = OrderPay.getTime(createTime + 1800000);// 三十分鐘後超時 10000毫秒=10秒
//啓動的時候找到需要的訂單信息
List<GoodsOrder> goodsOrders = goodsOrderRepository.findBy("status","1");
//循環訂單信息 把需要的信息 放進隊列的實體類
goodsOrders.forEach((info)->{
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderNo(info.getOrderNum());
orderInfo.setStatus(info.getStatus());
orderInfo.setCreateTime(currentTime);
orderInfo.setExpTime(overTime);
orderPutQueue(orderInfo,currentTime,overTime);
});
mainThread = new Thread(() -> execute());
mainThread.setDaemon(true);
mainThread.setName("守護線程-->");
mainThread.start();
}
/**
* 創建空延時隊列
*/
private DelayQueue<OrderInfo> queue = new DelayQueue<OrderInfo>();
/**
* 讀取延時隊列,關閉超時訂單
*/
private void execute() {
while (true) {
try {
if(queue.size() > 0){
//從隊列裏獲取超時的訂單
OrderInfo orderInfo = queue.take();
// 檢查訂單狀態,是否已經成功,成功則將訂單從隊列中刪除。
if (orderInfo.getStatus()>1) {
System.out.println("線程:"+Thread.currentThread().getName()+",訂單號:"
+ orderInfo.getOrderNo() + ",訂單狀態:"
+ orderInfo.getStatus() + ",訂單創建時間:"
+ orderInfo.getCreateTime()
+ ",訂單超時時間:" + orderInfo.getExpTime()+",當前時間:"+OrderPay.getTime(System.currentTimeMillis()));
orderRemoveQueue(orderInfo);
System.out.println("訂單已成功 移除掉"+orderInfo.getOrderNo());
Thread.sleep(2000);
} else {
//這裏是超時的訂單 把超時的訂單狀態改爲取消
GoodsOrderRepository goodsOrderRepository = ApplicationContextProvider.getBean(GoodsOrderRepository.class);
GoodsOrder goodsOrder = goodsOrderRepository.findOneBy("orderNum",orderInfo.getOrderNo());
if( goodsOrder!=null && goodsOrder.getStatus()<=1 )
{
goodsOrder.setStatus(GoodsOrder.orderType.cancelOrder);//取消訂單
goodsOrder.setCancelTime(new Date());
goodsOrderRepository.saveOrUpdate(goodsOrder);
}else
{
orderRemoveQueue(orderInfo);
System.out.println("訂單已成功 移除掉"+orderInfo.getOrderNo());
}
System.out.println("線程:"+Thread.currentThread().getName()+",訂單號:"
+ orderInfo.getOrderNo() + ",變更訂單狀態爲:超時關閉"
+ ",訂單創建時間:"
+ orderInfo.getCreateTime()
+ ",訂單超時時間:" + orderInfo.getExpTime()+",當前時間:"+OrderPay.getTime(System.currentTimeMillis()));
Thread.sleep(2000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 插入訂單到超時隊列中
*/
public void orderPutQueue(OrderInfo orderInfo, String createTime,
String overTime) {
System.out.println("訂單號:" + orderInfo.getOrderNo() + ",訂單創建時間:"
+ createTime + ",訂單過期時間:" + overTime);
queue.add(orderInfo);
}
/**
* 從延遲隊列中移除
*/
public void orderRemoveQueue(OrderInfo orderInfo){
if(null == orderInfo){
return;
}
for (Iterator<OrderInfo> iterator = queue.iterator(); iterator.hasNext();) {
OrderInfo info = (OrderInfo) iterator.next();
if(orderInfo.getOrderNo().equals(info.getOrderNo())){
queue.remove(info);
}
}
}
}
創建一個測試類
/**
* 模擬訂單支付,創建訂單
*/
public class OrderPay
{
static Integer[] str = new Integer[]{1,2,3};
public static String getTime(long time){
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(time);
String currentTime = formatter.format(date);
return currentTime;
}
public static void main(String[] args) throws InterruptedException {
OrderOverTimeClose.getInstance().init();
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 2; i++) {
Runnable run = new Runnable() {
@Override
public void run() {
// 創建初始訂單
long createTime = System.currentTimeMillis();
String currentTime = getTime(createTime);
String overTime = getTime(createTime + 10000);// 十秒後超時
String orderNo = String.valueOf(new Random().nextLong());
OrderInfo order = new OrderInfo();
order.setOrderNo(orderNo);
order.setExpTime(overTime);
int random_index = (int) (Math.random()*str.length);
order.setStatus(str[random_index]);// 隨機分配
order.setCreateTime(currentTime);
OrderOverTimeClose.getInstance().orderPutQueue(order, currentTime, overTime);
}
};
service.execute(run);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
好了 去試試吧 如果那裏錯了 或者不懂得 請指出來 Vx 號 AiMyHear