一、基於註解@Scheduled默認爲單線程
直接複製本類即可
/**
* @author yimocha
* @Configuration 主要用於標記配置類,兼備Component的效果。
* @EnableScheduling 開啓定時任務
*/
@Configuration
@EnableScheduling
@Slf4j
public class MyTask {
/**
* 添加定時任務
* 基於註解@Scheduled默認爲單線程,開啓多個任務時,任務的執行時機會受上一個任務執行時間的影響。
*
* @Scheduled(cron = "0/6 * * * * ?")
* 或直接指定時間間隔,例如:6秒
* @Scheduled(fixedRate=6000) 從上一任務開始執行後6s再次調用
*/
@Scheduled(cron = "0/6 * * * * ?")
private void myTaskOne() {
log.info("執行靜態定時任務時間: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}
Cron表達式:
@Scheduled:
除了支持靈活的參數表達式cron之外,還支持簡單的延時操作,
例如: fixedDelay ,fixedRate 填寫相應的毫秒數即可。
@Scheduled(fixedRate=6000) 週期是以上一個任務開始時間爲基準,從上一任務開始執行後6s再次調用
@Scheduled(fixedDelay=5000) 週期是以上一個調用任務的完成時間爲基準,在上一個任務完成之後,5s後再次執行
@Scheduled(initialDelay=1000, fixedRate=6000) 固定延遲和固定速率的任務,可以指定一個初始延遲表示該方法在第一被調用執行之前等待的毫秒數
二、數據庫動態:基於接口(SchedulingConfigurer)
實際使用中我們往往想從數據庫中讀取指定時間來動態執行定時任務,這時候基於接口的定時任務就是我們想要的。
task表數據
DROP TABLE IF EXISTS `task`;
CREATE TABLE `task` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key_code` varchar(64) DEFAULT '' COMMENT '任務鍵碼',
`cron` varchar(64) DEFAULT '' COMMENT 'Cron表達式參數',
`details` varchar(255) DEFAULT '' COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
INSERT INTO `task` VALUES ('1', 'task_one', '0/10 * * * * ?', '任務一');
數據庫持久層 mybatis-plus
java代碼
/**
* @Author yimocha
* @Configuration 主要用於標記配置類,兼備Component的效果。
* @EnableScheduling 開啓定時任務
**/
@Configuration
@EnableScheduling
public class MyTaskTow implements SchedulingConfigurer {
@Autowired
TaskMapper taskMapper;
/**
* 執行定時任務
* @param scheduledTaskRegistrar
*/
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(
//1.添加任務內容(Runnable)
() -> System.out.println("執行動態定時任務: " + LocalDateTime.now().toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"))),
//2.設置執行週期(Trigger)
triggerContext -> {
// 查詢數據庫的數據
String cron = taskMapper.selectById(1).getCron();
// 合法性校驗.
if (StringUtils.isEmpty(cron)) {
System.out.println("cron爲空,執行默認corn,間隔5秒執行");
cron = "0/5 * * * * ?";
}
// 返回執行週期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
如果在數據庫修改時格式出現錯誤,則定時任務會停止,即使重新修改正確;此時只能重新啓動項目才能恢復。
三、多線程的定時任務
/**
* @Component 註解用於對那些比較中立的類進行註釋;
* 相對與在持久層、業務層和控制層分別採用 @Repository、@Service 和 @Controller 對分層中的類進行註釋
* @EnableScheduling 開啓定時任務
* @EnableAsync 開啓多線程
*/
@Component
@EnableScheduling
@EnableAsync
public class MultithreadScheduleTask {
/**
* @throws InterruptedException
* @Async
* @Scheduled(fixedDelay = 3000) 在上一個任務完成之後,3s後再次執行
*/
@Async
@Scheduled(fixedDelay = 3000)
public void first() throws InterruptedException {
System.out.println("第一個定時任務開始 : " + LocalDateTime.now().toLocalTime() + "\r\n線程 : " + Thread.currentThread().getName());
System.out.println();
Thread.sleep(1000 * 10);
}
/**
* @throws InterruptedException
* @Async
* @Scheduled(fixedDelay = 5000) 在上一個任務完成之後,5s後再次執行
*/
@Async
@Scheduled(fixedDelay = 5000)
public void second() {
System.out.println("第二個定時任務開始 : " + LocalDateTime.now().toLocalTime() + "\r\n線程 : " + Thread.currentThread().getName());
System.out.println();
}
}
開啓了多線程,第一個任務的執行時間也不受其本身執行時間的限制,所以需要注意可能會出現重複操作導致數據異常