中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

springboot執行延時任務之DelayQueue的使用詳解

發布時間:2020-09-28 21:22:13 來源:腳本之家 閱讀:1438 作者:依天照海 欄目:編程語言

DelayQueue簡介

DelayQueue是一個無界阻塞隊列,只有在延遲期滿時,才能從中提取元素。
隊列的頭部,是延遲期滿后保存時間最長的delay元素。

在很多場景我們需要用到延時任務,比如給客戶異步轉賬操作超時后發通知告知用戶,還有客戶下單后多長時間內沒支付則取消訂單等等,這些都可以使用延時任務來實現。

jdk中DelayQueue可以實現上述需求,顧名思義DelayQueue就是延時隊列。

DelayQueue提供了在指定時間才能獲取隊列元素的功能,隊列頭元素是最接近過期的元素。

沒有過期元素的話,使用poll()方法會返回null值,超時判定是通過getDelay(TimeUnit.NANOSECONDS)方法的返回值小于等于0來判斷。

延時隊列不能存放空元素。

一般使用take()方法阻塞等待,有過期元素時繼續。

隊列元素說明

DelayQueue<E extends Delayed>的隊列元素需要實現Delayed接口,該接口類定義如下:

public interface Delayed extends Comparable<Delayed> {

 /**
  * Returns the remaining delay associated with this object, in the
  * given time unit.
  *
  * @param unit the time unit
  * @return the remaining delay; zero or negative values indicate
  * that the delay has already elapsed
  */
 long getDelay(TimeUnit unit);
}

所以DelayQueue的元素需要實現getDelay方法和Comparable接口的compareTo方法,getDelay方法來判定元素是否過期,compareTo方法來確定先后順序。

springboot中實例運用

DelayTask就是隊列中的元素

import java.util.Date;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class DelayTask implements Delayed {
 final private TaskBase data;
 final private long expire;
 /**
  * 構造延時任務
  * @param data  業務數據
  * @param expire 任務延時時間(ms)
  */
 public DelayTask(TaskBase data, long expire) {
  super();
  this.data = data;
  this.expire = expire + System.currentTimeMillis();
 }
 public TaskBase getData() {
  return data;
 }
 public long getExpire() {
  return expire;
 }
 @Override
 public boolean equals(Object obj) {
  if (obj instanceof DelayTask) {
   return this.data.getIdentifier().equals(((DelayTask) obj).getData().getIdentifier());
  }
  return false;
 }
 @Override
 public String toString() {
  return "{" + "data:" + data.toString() + "," + "expire:" + new Date(expire) + "}";
 }
 @Override
 public long getDelay(TimeUnit unit) {
  return unit.convert(this.expire - System.currentTimeMillis(), unit);
 }
 @Override
 public int compareTo(Delayed o) {
  long delta = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
  return (int) delta;
 }
}

TaskBase類是用戶自定義的業務數據基類,其中有一個identifier字段來標識任務的id,方便進行索引

import com.alibaba.fastjson.JSON;
public class TaskBase {
 private String identifier;
 public TaskBase(String identifier) {
  this.identifier = identifier;
 }
 public String getIdentifier() {
  return identifier;
 }
 public void setIdentifier(String identifier) {
  this.identifier = identifier;
 }
 @Override
 public String toString() {
  return JSON.toJSONString(this);
 }
}

定義一個延時任務管理類DelayQueueManager,通過@Component注解加入到spring中管理,在需要使用的地方通過@Autowire注入

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executors;
@Component
public class DelayQueueManager implements CommandLineRunner {
 private final Logger logger = LoggerFactory.getLogger(DelayQueueManager.class);
 private DelayQueue<DelayTask> delayQueue = new DelayQueue<>();
 /**
  * 加入到延時隊列中
  * @param task
  */
 public void put(DelayTask task) {
  logger.info("加入延時任務:{}", task);
  delayQueue.put(task);
 }
 /**
  * 取消延時任務
  * @param task
  * @return
  */
 public boolean remove(DelayTask task) {
  logger.info("取消延時任務:{}", task);
  return delayQueue.remove(task);
 }
 /**
  * 取消延時任務
  * @param taskid
  * @return
  */
 public boolean remove(String taskid) {
  return remove(new DelayTask(new TaskBase(taskid), 0));
 }
 @Override
 public void run(String... args) throws Exception {
  logger.info("初始化延時隊列");
  Executors.newSingleThreadExecutor().execute(new Thread(this::excuteThread));
 }
 /**
  * 延時任務執行線程
  */
 private void excuteThread() {
  while (true) {
   try {
    DelayTask task = delayQueue.take();
    processTask(task);
   } catch (InterruptedException e) {
    break;
   }
  }
 }
 /**
  * 內部執行延時任務
  * @param task
  */
 private void processTask(DelayTask task) {
  logger.info("執行延時任務:{}", task);
  //根據task中的data自定義數據來處理相關邏輯,例 if (task.getData() instanceof XXX) {}
 }
}

DelayQueueManager實現了CommandLineRunner接口,在springboot啟動完成后就會自動調用run方法。

總結

以上所述是小編給大家介紹的springboot執行延時任務DelayQueue的使用詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

米易县| 方山县| 枝江市| 江门市| 黄浦区| 辽中县| 沙雅县| 茂名市| 长兴县| 墨竹工卡县| 安图县| 小金县| 河间市| 兴化市| 广西| 新沂市| 白朗县| 洛川县| 五河县| 正安县| 班戈县| 潞西市| 林州市| 漳平市| 安溪县| 淄博市| 金山区| 东乌珠穆沁旗| 常山县| 嘉善县| 长顺县| 龙山县| 昆山市| 宣恩县| 文安县| 乳源| 仙游县| 合作市| 闽清县| 信丰县| 沙雅县|