您好,登錄后才能下訂單哦!
今天小編給大家分享一下Java如何實現定時任務的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
Timer是JAVA自帶的定時任務類,實現如下:
public class MyTimerTask { public static void main(String[] args) { // 定義一個任務 TimerTask timerTask = new TimerTask() { @Override public void run() { System.out.println("打印當前時間:" + new Date()); } }; // 計時器 Timer timer = new Timer(); // 開始執行任務 (延遲1000毫秒執行,每3000毫秒執行一次) timer.schedule(timerTask, 1000, 3000); } }
Timer 優缺點分析
優點是使用簡單,缺點是當添加并執行多個任務時,前面任務的執行用時和異常將影響到后面任務,這邊深海建議謹慎使用。
ScheduledExecutorService 也是Java自帶的類,
它可以實現Timer具備的所有功能,并解決了 Timer類存在的問題。
實現如下:
public class MyScheduledExecutorService { public static void main(String[] args) { // 創建任務隊列 10 為線程數量 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); // 執行任務 scheduledExecutorService.scheduleAtFixedRate(() -> { System.out.println("打印當前時間:" + new Date()); }, 1, 3, TimeUnit.SECONDS); // 1s 后開始執行,每 3s 執行一次 } }
ScheduledExecutorService 優缺點分析
優點是,該類是JDK1.5自帶的類,使用簡單,缺點是該方案僅適用于單機環境。
Spring系列框架中Spring Framework自帶的定時任務,
使用上面兩種方式,很難實現某些特定需求,比如每周一執行某任務,但SpringTask可輕松實現。
以SpringBoot為例來實現:
在SpringBoot的啟動類上聲明 @EnableScheduling:
@SpringBootApplication @EnableScheduling //開啟定時任務 public class DemoApplication { // -- -- }
只需使用@Scheduled注解標注即可,
如果有多個定時任務,可以創建多個@Scheduled標注的方法,示例如下:
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component // 把此類托管給 Spring,不能省略 public class TaskUtils { // 添加定時任務 @Scheduled(cron = "30 40 23 0 0 5") // cron表達式:每周一 23:40:30 執行 public void doTask(){ System.out.println("我是定時任務~"); } }
Spring Boot 啟動后會自動加載并執行定時任務,無需手動操作。
Spring Task 的實現需要使用 cron 表達式來聲明執行的頻率和規則,cron 表達式是由 6 位或者 7 位組成的(最后一位可以省略),每位之間以空格分隔,每位從左到右代表的含義如下:
其中 * 和 ? 號都表示匹配所有的時間。
上面的方法都是關于單機定時任務的實現,如果是分布式環境可以使用 Redis 來實現定時任務。
使用 Redis 實現延遲任務的方法大體可分為兩類:通過 ZSet 的方式和鍵空間通知的方式。
通過 ZSet 實現定時任務的思路是,將定時任務存放到 ZSet 集合中,并且將過期時間存儲到 ZSet 的 Score 字段中,然后通過一個無線循環來判斷當前時間內是否有需要執行的定時任務,如果有則進行執行,具體實現代碼如下:
import redis.clients.jedis.Jedis; import utils.JedisUtils; import java.time.Instant; import java.util.Set; public class DelayQueueExample { private static final String _KEY = "DelayQueueExample"; public static void main(String[] args) throws InterruptedException { Jedis jedis = JedisUtils.getJedis(); // 30s 后執行 long delayTime = Instant.now().plusSeconds(30).getEpochSecond(); jedis.zadd(_KEY, delayTime, "order_1"); // 繼續添加測試數據 jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_2"); jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_3"); jedis.zadd(_KEY, Instant.now().plusSeconds(7).getEpochSecond(), "order_4"); jedis.zadd(_KEY, Instant.now().plusSeconds(10).getEpochSecond(), "order_5"); // 開啟定時任務隊列 doDelayQueue(jedis); } /** * 定時任務隊列消費 * @param jedis Redis 客戶端 */ public static void doDelayQueue(Jedis jedis) throws InterruptedException { while (true) { // 當前時間 Instant nowInstant = Instant.now(); long lastSecond = nowInstant.plusSeconds(-1).getEpochSecond(); // 上一秒時間 long nowSecond = nowInstant.getEpochSecond(); // 查詢當前時間的所有任務 Set data = jedis.zrangeByScore(_KEY, lastSecond, nowSecond); for (String item : data) { // 消費任務 System.out.println("消費:" + item); } // 刪除已經執行的任務 jedis.zremrangeByScore(_KEY, lastSecond, nowSecond); Thread.sleep(1000); // 每秒查詢一次 } } }
我們可以通過 Redis 的鍵空間通知來實現定時任務,它的實現思路是給所有的定時任務設置一個過期時間,等到了過期之后,我們通過訂閱過期消息就能感知到定時任務需要被執行了,此時我們執行定時任務即可。
默認情況下 Redis 是不開啟鍵空間通知的,需要我們通過 config set notify-keyspace-events Ex 的命令手動開啟,開啟之后定時任務的代碼如下:
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPubSub; import utils.JedisUtils; public class TaskExample { public static final String _TOPIC = "__keyevent@0__:expired"; // 訂閱頻道名稱 public static void main(String[] args) { Jedis jedis = JedisUtils.getJedis(); // 執行定時任務 doTask(jedis); } /** * 訂閱過期消息,執行定時任務 * @param jedis Redis 客戶端 */ public static void doTask(Jedis jedis) { // 訂閱過期消息 jedis.psubscribe(new JedisPubSub() { @Override public void onPMessage(String pattern, String channel, String message) { // 接收到消息,執行定時任務 System.out.println("收到消息:" + message); } }, _TOPIC); } }
以上就是“Java如何實現定時任務”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。