SpringBoot定時調(diào)度之Timer與Quartz詳解
Java 中常用的定時調(diào)度框架有以下幾種:
- Timer:Java 標準庫中提供的一個定時調(diào)度工具,可以在指定的時間點或時間間隔內(nèi)執(zhí)行任務。Timer 的缺點是不支持并發(fā)執(zhí)行和錯誤處理機制較弱。
- ScheduledExecutorService:Java 標準庫中提供的另一個定時調(diào)度工具,也可以在指定的時間點或時間間隔內(nèi)執(zhí)行任務。與 Timer 相比,ScheduledExecutorService 支持并發(fā)執(zhí)行和錯誤處理機制較強。
- Spring Task:Spring 框架中提供的一個定時調(diào)度工具,可以用于執(zhí)行定時任務、異步任務等。Spring Task 支持多種時間表達式、動態(tài)調(diào)整和錯誤處理機制。
- Quartz:一個用于定時調(diào)度的開源框架,可以在指定的時間點或時間間隔內(nèi)自動執(zhí)行任務。Quartz 支持多種配置方式和調(diào)度策略,功能豐富、靈活性高、易于集成并且可靠性較高。
Timer
Timer 是 Java 標準庫中提供的一個定時調(diào)度工具,可以在指定的時間點或時間間隔內(nèi)執(zhí)行任務。Timer 提供了多種調(diào)度方式和執(zhí)行策略,可以用于管理簡單的定時任務。
Timer 使用 TimerTask 類來表示要執(zhí)行的任務,TimerTask 是一個抽象類,需要繼承并實現(xiàn) run() 方法來定義具體的任務邏輯。Timer 還提供了多種調(diào)度方式,包括定時調(diào)度、周期性調(diào)度等。
以下是一個簡單的 Timer 示例:
import java.util.Timer;
import java.util.TimerTask;
public class MyTask extends TimerTask {
public void run() {
System.out.println("定時任務執(zhí)行了!");
}
public static void main(String[] args) {
Timer timer = new Timer();
MyTask task = new MyTask();
timer.schedule(task, 5000); // 5秒后執(zhí)行任務
}
}在上述代碼中,我們定義了一個名為 MyTask 的 TimerTask 類,并在其中實現(xiàn)了 run() 方法來定義具體的任務邏輯。然后,在 main() 方法中創(chuàng)建了一個 Timer 實例,并使用 schedule() 方法來指定任務的執(zhí)行時間和執(zhí)行方式。
需要注意的是,Timer 的缺點是不支持并發(fā)執(zhí)行和錯誤處理機制較弱。如果需要實現(xiàn)復雜的定時任務,可以考慮使用其它的定時調(diào)度框架,例如 Quartz、ScheduledExecutorService 等。
ScheduledExecutorService
ScheduledExecutorService 基于 Executor 框架,使用 ThreadPoolExecutor 來實現(xiàn)任務的執(zhí)行和管理。
好的,下面是一個使用 ScheduledExecutorService 實現(xiàn)每天凌晨1點執(zhí)行任務的示例:
import java.time.LocalTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MyTask implements Runnable {
public void run() {
System.out.println("定時任務執(zhí)行了!當前時間:" + LocalTime.now());
}
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
MyTask task = new MyTask();
long initialDelay = calculateInitialDelay();
executor.scheduleAtFixedRate(task, initialDelay, 24, TimeUnit.HOURS); // 每天凌晨1點執(zhí)行任務
}
private static long calculateInitialDelay() {
LocalTime now = LocalTime.now();
LocalTime target = LocalTime.of(1, 0, 0); // 目標執(zhí)行時間為每天凌晨1點
if (now.isBefore(target)) {
return Duration.between(now, target).toMillis();
} else {
return Duration.between(now, target.plusDays(1)).toMillis();
}
}
}在上述代碼中,我們定義了一個名為 MyTask 的 Runnable 類,并在其中實現(xiàn)了 run() 方法來定義具體的任務邏輯。然后,在 main() 方法中創(chuàng)建了一個 ScheduledExecutorService 實例,并使用 scheduleAtFixedRate() 方法來指定任務的執(zhí)行時間和執(zhí)行方式。
為了實現(xiàn)每天凌晨1點執(zhí)行任務,我們先定義了一個 calculateInitialDelay() 方法來計算任務的初始延遲時間。該方法會根據(jù)當前時間和目標執(zhí)行時間計算出初始延遲時間,如果當前時間早于目標執(zhí)行時間,則將初始延遲時間設(shè)置為兩者時間差,否則將初始延遲時間設(shè)置為兩者時間差加上一天的時間差。
最后,我們使用 scheduleAtFixedRate() 方法來指定任務的執(zhí)行時間和執(zhí)行周期,其中 initialDelay 參數(shù)為初始延遲時間,period 參數(shù)為執(zhí)行周期,這里是每24小時執(zhí)行一次。
需要注意的是,為了獲取當前時間和計算時間差,我們使用了 Java 8 中的 LocalDate、LocalTime 和 Duration 類。如果使用的是 Java 7 或更早的版本,可以使用 Date、Calendar 等類來代替。
Spring Task
Spring Task(也稱為 Spring Scheduler)是 Spring 框架中提供的定時任務框架,可以在指定的時間點或時間間隔內(nèi)執(zhí)行任務。Spring Task 封裝了 Java 標準庫中的 Timer 和ScheduledExecutorService,提供了更加簡單和方便的定時任務管理方式。
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyTask {
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1點執(zhí)行任務
public void execute() {
System.out.println("定時任務執(zhí)行了!當前時間:" + new Date());
}
}在上述代碼中,我們定義了一個名為 MyTask 的類,并在其中使用 @Scheduled 注解來指定任務的執(zhí)行時間和執(zhí)行方式。這里使用了 cron 表達式來指定每天凌晨1點執(zhí)行任務。
@Scheduled注解支持多種參數(shù)設(shè)置,例如:
- fixedRate:表示每隔多少毫秒執(zhí)行一次。
- fixedDelay:表示延遲多少毫秒后執(zhí)行。
- initialDelay:表示啟動延遲多少毫秒后執(zhí)行第一次。
- cron:使用Cron表達式來指定執(zhí)行時間,例如“0 0 12 * * ?”表示每天中午12點執(zhí)行。
需要注意的是,@Scheduled注解只能用于Spring容器中的Bean中,因此需要將使用該注解的類標注為@Component或其他的Spring組件注解。
cron表達式
| 任務執(zhí)行時間 | cron 表達式 |
|---|---|
| 每分鐘執(zhí)行一次 | 0 * * * * ? |
| 每小時的第30分鐘執(zhí)行一次 | 0 30 * * * ? |
| 每天的凌晨1點執(zhí)行一次 | 0 0 1 * * ? |
| 每周的周日凌晨1點執(zhí)行一次 | 0 0 1 ? * SUN |
| 每月的1號凌晨1點執(zhí)行一次 | 0 0 1 1 * ? |
| 每年的1月1日凌晨1點執(zhí)行一次 | 0 0 1 1 1 ? |
| 每天上午10點和下午2點執(zhí)行一次 | 0 0 10,14 * * ? |
| 每天的上午10點到11點之間每隔30秒執(zhí)行一次 | 0/30 10-11 * * * ? |
| 每天的上午10點到11點之間每隔5分鐘的1、6、11、16、21、26、31、36、41、46、51、56秒執(zhí)行 | 1,6,11,16,21,26,31,36,41,46,51,56 10-11 * * * ? |
另外,如果想要快速生成 cron 表達式,可以使用在線 cron 表達式生成器,例如 cron.qqe2.com/ cron 表達式。
@EnableScheduling
使用@Scheduled需要@EnableScheduling 配合,默認 spring-boot-actuator 包會帶上@EnableScheduling 注解,從而給人一種默認開啟定時任務的錯覺。移除對應包之后,如果用戶沒有在自己項目中帶上 @EnableScheduling 注解,則定時任務不會生效。
Quartz
Quartz 使用 Job 和 Trigger 兩個核心概念來管理任務。Job 表示要執(zhí)行的任務,Trigger 表示任務的觸發(fā)器,即任務執(zhí)行的時間條件。Quartz 還提供了多種調(diào)度器和監(jiān)聽器,可以實現(xiàn)更加復雜的任務調(diào)度和任務管理。
以下是一個簡單的 Quartz 示例:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class MyJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("定時任務執(zhí)行了!當前時間:" + new Date());
}
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group1").build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")
.startAt(DateBuilder.todayAt(1, 0, 0)).withSchedule(SimpleScheduleBuilder.repeatHourlyForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
}
}在上述代碼中,我們定義了一個名為 MyJob 的 Job 類,并在其中實現(xiàn)了 execute() 方法來定義具體的任務邏輯。然后,在 main() 方法中創(chuàng)建了一個 Scheduler 實例,并使用 JobBuilder 和 TriggerBuilder 來定義任務和觸發(fā)器。這里我們使用 SimpleScheduleBuilder 來指定任務的執(zhí)行間隔,即每小時執(zhí)行一次。
Quartz 還支持多種觸發(fā)器類型和調(diào)度器類型,例如 CronTrigger、CalendarIntervalTrigger、JobStoreTX 等,可以根據(jù)具體的需求進行選擇和配置。
以上就是SpringBoot定時調(diào)度之Timer與Quartz詳解的詳細內(nèi)容,更多關(guān)于SpringBoot定時的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實現(xiàn)學生信息管理系統(tǒng)IO版本
這篇文章主要為大家詳細介紹了Java實現(xiàn)學生信息管理系統(tǒng)IO版本,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-04-04
SpringSecurity Demo 創(chuàng)建項目的過程詳解
本文介紹了使用SpringBoot 3.2.4創(chuàng)建一個簡單的安全驗證項目的過程,包括引入依賴、配置文件修改、創(chuàng)建控制器和啟動類等步驟,并最終成功啟動項目并在瀏覽器訪問到請求接口,感興趣的朋友跟隨小編一起看看吧2026-04-04
pdf2swf+flexpapers實現(xiàn)類似百度文庫pdf在線閱讀
這篇文章主要介紹了pdf2swf+flexpapers實現(xiàn)類似百度文庫pdf在線閱讀的相關(guān)資料,需要的朋友可以參考下2014-10-10
Java中double和float類型的區(qū)別與使用方法
float和double都是用來表示浮點數(shù)的數(shù)據(jù)類型,但是它們之間有一些區(qū)別,這篇文章主要給大家介紹了關(guān)于Java中double和float類型的區(qū)別與使用方法的相關(guān)資料,需要的朋友可以參考下2024-07-07
基于Java實現(xiàn)回調(diào)監(jiān)聽工具類
這篇文章主要為大家詳細介紹了如何基于Java實現(xiàn)一個回調(diào)監(jiān)聽工具類,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2025-04-04
SpringBoot整合數(shù)據(jù)庫連接池Druid的錯誤詳解
文章總結(jié)了幾種SpringBoot整合Druid時遇到的問題及其解決方法,主要問題有:缺少jar包導致系統(tǒng)停止和ClassNotFoundException,通過添加缺少的jar包可以解決問題,同時提醒注意數(shù)據(jù)庫配置信息的正確性和避免jar包沖突2026-04-04
Java版本兼容性之JDK 21的SDK在JDK 1.8的使用解讀
文章介紹了Java的字節(jié)碼版本機制以及如何處理UnsupportedClassVersionError錯誤,文章首先解釋了JVM如何通過檢查.class文件的字節(jié)碼版本號來確定是否可以運行該文件,然后給出了三個解決方案:統(tǒng)一環(huán)境、交叉編譯和多版本JAR2025-11-11

