淺析SpringBoot如何做定時任務:@EnableScheduling和@Scheduled的使用、參數配置以及需要注意的內存問題


  定時任務相當於鬧鍾,在什么時間做什么事情(執行什么命令/腳本)。

  @EnableScheduling 在配置類上使用,開啟計划任務的支持  ——  用於類上。

  @Scheduled 來聲明這是一個任務,包括cron、fixDelay、fixRate等類型  ——  用於方法上,需先開啟計划任務的支持

一、如何使用

1、pom.xml 中導入必要的依賴

2、啟動類里面使用@EnableScheduling 注解開啟功能,自動掃描

@SpringBootApplication @EnableScheduling //開啟定時任務
public class MainApplication { ...... }

3、在類上加上:在任務方法上寫 @Scheduled

@Service public class TestService2 { private static final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss"); //初始延遲1秒,每隔2秒
    @Scheduled(fixedRateString = "2000",initialDelay = 1000) public void testFixedRate(){ System.out.println("fixedRateString,當前時間:" +format.format(new Date())); } //每次執行完延遲2秒
    @Scheduled(fixedDelayString= "2000") public void testFixedDelay(){ System.out.println("fixedDelayString,當前時間:" +format.format(new Date())); } //每隔3秒執行一次
    @Scheduled(cron="0/3 * * * * ?") public void testCron(){ System.out.println("cron,當前時間:" +format.format(new Date())); } }

二、Scheduled注解中有以下幾個參數:

1、cron表達式  ——  比如你要設置每天什么時候執行,就可以用它。

cron表達式,有專門的語法,而且感覺有點繞人,不過簡單來說,大家記住一些常用的用法即可,特殊的語法可以單獨去查。cron一共有7位,但是最后一位是年,可以留空,所以我們可以寫6位:
第一位,表示秒,取值0-59 第二位,表示分,取值0-59 第三位,表示小時,取值0-23 第四位,日期天/日,取值1-31 第五位,日期月份,取值1-12 第六位,星期,取值1-7,星期一,星期二...,注:不是第1周,第二周的意思;另外:1表示星期天,2表示星期一。 第7為,年份,可以留空,取值1970-2099

  cron中,還有一些特殊的符號,含義如下:

(*) 星號:可以理解為每的意思,每秒,每分,每天,每月,每年... (?) 問號:問號只能出現在日期和星期這兩個位置。 (-) 減號:表達一個范圍,如在小時字段中使用“10-12”,則表示從10到12點,即10,11,12 (,) 逗號:表達一個列表值,如在星期字段中使用“1,2,4”,則表示星期一,星期二,星期四 (/) 斜杠:如:x/y,x是開始值,y是步長,
比如在第一位(秒) 0/15就是,從0秒開始,每15秒,最后就是0,15,30,45,60 另:*/y,等同於0/y

  下面列舉幾個例子供大家來驗證:

0 0 3 * * ? 每天3點執行 0 5 3 * * ? 每天3點5分執行 0 5 3 ? * * 每天3點5分執行,與上面作用相同 0 5/10 3 * * ? 每天3點的 5分,15分,25分,35分,45分,55分這幾個時間點執行 0 10 3 ? * 1 每周星期天,3點10分 執行,注:1表示星期天 0 10 3 ? * 1#3  每個月的第三個星期,星期天 執行,#號只能出現在星期的位置

2、zone  ——  表示執行時間的時區

3、fixedDelay 和 fixedDelayString  ——  表示一個固定延遲時間執行,上個任務完成后,延遲多長時間執行

4、fixedRate 和 fixedRateString  ——  表示一個固定頻率執行,上個任務開始后,多長時間后開始執行

5、initialDelay 和initialDelayString表示一個初始延遲時間,第一次被調用前延遲的時間

  需要注意的是 cron、fixedDelay、fixedRate 必須得有一個,否則會報錯:Encountered invalid @Scheduled method 'updateBookNum': Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required

三、注解參數區別

  @Scheduled注解可以控制方法定時執行,其中有三個參數可選擇:

1、fixedDelay控制方法執行的間隔時間,是以上一次方法執行完開始算起,如上一次方法執行阻塞住了,那么直到上一次執行完,並間隔給定的時間后,執行下一次。

2、fixedRate是按照一定的速率執行,是從上一次方法執行開始的時間算起,如果上一次方法阻塞住了,下一次也是不會執行,但是在阻塞這段時間內累計應該執行的次數,當不再阻塞時,一下子把這些全部執行掉,而后再按照固定速率繼續執行。

3、cron表達式可以定制化執行任務,但是執行的方式是與fixedDelay相近的,也是會按照上一次方法結束時間開始算起。

4、initialDelay 。如: @Scheduled(initialDelay = 10000,fixedRate = 15000),這個定時器就是在上一個的基礎上加了一個initialDelay = 10000,意思就是在容器啟動后,延遲10秒后再執行一次定時器,以后每15秒再執行一次該定時器。

四、Scheduled定時任務會導致內存泄漏嗎?

1、要看你的定時任務是做什么的,只是調用無狀態的方法是不會占用內存的,就像你用for循環執行一個任務很多次一樣。但是,如果你在定時任務里進行一些影響全局的操作,例如不停地往一個List里append新的內容,當然會造成內存泄漏。或者說你在定時任務里新建一個以當前時間為文件名的文本文件,里面寫上一些內容,一段時間后你的磁盤空間都會爆滿的。總而言之會不會造成內存泄漏往往不是框架的問題,而是代碼自己的問題。

2、盡管Java提供了自動的垃圾回收機制,但是這不代表說開發者就可以完全不管程序內對象和數據結構的使用限制了,比如最常見的場景,假設你把new完的對象放在隊列或者Map里,然后這個定時任務不停地添加這種對象,那最后肯定會OOM的。GC只能回收那些沒有被引用的對象,而如果你個個都引用並且並不釋放(方法結束或者主動置為null,或者將存放的集合銷毀),那再無敵的GC也幫不了你。所以不要把所有希望都寄托在GC上面。

  所以在使用定時器的過程中,需要注意定時器里的內存溢出問題。定時器本身不會導致內存溢出,就是怕定時器里的代碼處理不好,加入無法被GC回收的對象,堆積導致內存溢出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM