您好,登錄后才能下訂單哦!
SpringBoot
?是為了簡化?Spring
?應用的創建、運行、調試、部署等一系列問題而誕生的產物,自動裝配的特性讓我們可以更好的關注業務本身而不是外部的XML配置,我們只需遵循規范,引入相關的依賴就可以輕易的搭建出一個 WEB 工程
在我們日常開發中,經常會遇到?數據定時增量同步、定時發送郵件、爬蟲定時抓取 的需求;這時我們可以采用定時任務
的方式去進行工作…..
定時任務:顧名思義就是在指定/特定的時間進行工作,比如我們的手機鬧鐘,它就是一種定時任務。
實現方式
Timer:?JDK自帶的java.util.Timer
;通過調度java.util.TimerTask
的方式?讓程序按照某一個頻度執行,但不能在指定時間運行。?一般用的較少。
ScheduledExecutorService:?JDK1.5新增的,位于java.util.concurrent
包中;是基于線程池設計的定時任務類,每個調度任務都會被分配到線程池中,并發執行,互不影響。
Spring Task:?Spring3.0 以后新增了task
,一個輕量級的Quartz
,功能夠用,用法簡單。
Quartz:?功能最為強大的調度器,可以讓程序在指定時間執行,也可以按照某一個頻度執行,它還可以動態開關,但是配置起來比較復雜。現如今開源社區中已經很多基于Quartz 實現的分布式定時任務項目
(xxl-job、elastic-job)。
基于?Timer
?實現的定時調度,基本就是手擼代碼,目前應用較少,不是很推薦
package com.battcn.timer;
import java.time.LocalDateTime;
import java.util.Timer;
import java.util.TimerTask;
/**
* 基于Timer實現的定時調度(不推薦,用該方式不如用 ScheduledExecutorService )
*
* @author Levin
* @since 2018/5/29 0029
*/
public class TimerDemo {
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("執行任務:" + LocalDateTime.now());
}
};
Timer timer = new Timer();
// timerTask:需要執行的任務
// delay:延遲時間(以毫秒為單位)
// period:間隔時間(以毫秒為單位)
timer.schedule(timerTask, 5000, 3000);
}
}
與Timer
很類似,但它的效果更好,多線程并行處理定時任務時,Timer
運行多個TimeTask
時,只要其中有一個因任務報錯沒有捕獲拋出的異常,其它任務便會自動終止運行,使用 ScheduledExecutorService 則可以規避這個問題
package com.battcn.scheduled;
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 基于 ScheduledExecutorService 方式,相對的比 Timer 要好
*
* @author Levin
* @since 2018/5/29 0029
*/
public class ScheduledExecutorServiceDemo {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
// 參數:1、具體執行的任務 2、首次執行的延時時間
// 3、任務執行間隔 4、間隔時間單位
service.scheduleAtFixedRate(() -> System.out.println("執行任務A:" + LocalDateTime.now()), 0, 3, TimeUnit.SECONDS);
}
}
在?pom.xml
?中添加?spring-boot-starter-web
?依賴即可,它包含了spring-context
,定時任務相關的就屬于這個JAR下的org.springframework.scheduling
包中
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
@Scheduled
?定時任務的核心
fixedRate
屬性不同的是它是將時間進行了切割。(@Scheduled(cron = "0/5 * * * * *")
任務將在5、10、15、20...
這種情況下進行工作)@Scheduled(fixedRate = 1000)
?假設第一次工作時間為2018-05-29 16:58:28
,工作時長為3秒
,那么下次任務的時候就是2018-05-29 16:58:31
)@Scheduled(fixedDelay = 3000)
?假設第一次任務工作時間為2018-05-29 16:54:33
,工作時長為5秒
,那么下次任務的時間就是2018-05-29 16:54:41
)fixedDelay
關系密切,配合使用,相輔相成。
@Async
?代表該任務可以進行異步工作,由原本的串行改為并行
package com.battcn.task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* 基于 Spring 自帶的
*
* @author Levin
* @since 2018/5/29 0029
*/
@Component
public class SpringTaskDemo {
private static final Logger log = LoggerFactory.getLogger(SpringTaskDemo.class);
@Async
@Scheduled(cron = "0/1 * * * * *")
public void scheduled1() throws InterruptedException {
Thread.sleep(3000);
log.info("scheduled1 每1秒執行一次:{}", LocalDateTime.now());
}
@Scheduled(fixedRate = 1000)
public void scheduled2() throws InterruptedException {
Thread.sleep(3000);
log.info("scheduled2 每1秒執行一次:{}", LocalDateTime.now());
}
@Scheduled(fixedDelay = 3000)
public void scheduled3() throws InterruptedException {
Thread.sleep(5000);
log.info("scheduled3 上次執行完畢后隔3秒繼續執行:{}", LocalDateTime.now());
}
}
cron表達式在線生成:?http://www.pdtools.net/tools/becron.jsp
@EnableScheduling
?注解表示開啟對@Scheduled
注解的解析;同時new ThreadPoolTaskScheduler()
也是相當的關鍵,通過閱讀過源碼可以發現默認情況下的?private volatile int poolSize = 1;
這就導致了多個任務的情況下容易出現競爭情況(多個任務的情況下,如果第一個任務沒執行完畢,后續的任務將會進入等待狀態)。
@EnableAsync
?注解表示開啟@Async
注解的解析;作用就是將串行化的任務給并行化了。(@Scheduled(cron = "0/1 * * * * *")
假設第一次工作時間為2018-05-29 17:30:55
,工作周期為3秒
;如果不加@Async
那么下一次工作時間就是2018-05-29 17:30:59
;如果加了@Async
?下一次工作時間就是2018-05-29 17:30:56
)
package com.battcn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* @author Levin
*/
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class Chapter15Application {
public static void main(String[] args) {
SpringApplication.run(Chapter15Application.class, args);
}
/**
* 很關鍵:默認情況下 TaskScheduler 的 poolSize = 1
*
* @return 線程池
*/
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
return taskScheduler;
}
}
完成準備事項后,啟動Chapter15Application
,觀察日志信息如下
2018-05-29 17:35:51.479 INFO 32640 --- [taskScheduler-1] com.battcn.task.SpringTaskDemo : scheduled2 每1秒執行一次:2018-05-29T17:35:51.479
2018-05-29 17:35:52.005 INFO 32640 --- [taskScheduler-3] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:52.005
2018-05-29 17:35:53.002 INFO 32640 --- [taskScheduler-5] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:53.002
2018-05-29 17:35:53.468 INFO 32640 --- [taskScheduler-2] com.battcn.task.SpringTaskDemo : scheduled3 上次執行完畢后隔3秒繼續執行:2018-05-29T17:35:53.468
2018-05-29 17:35:54.002 INFO 32640 --- [taskScheduler-6] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:54.002
2018-05-29 17:35:54.479 INFO 32640 --- [taskScheduler-7] com.battcn.task.SpringTaskDemo : scheduled2 每1秒執行一次:2018-05-29T17:35:54.479
2018-05-29 17:35:55.002 INFO 32640 --- [taskScheduler-8] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:55.002
2018-05-29 17:35:56.001 INFO 32640 --- [taskScheduler-1] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:56.001
2018-05-29 17:35:57.001 INFO 32640 --- [taskScheduler-3] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:57.001
2018-05-29 17:35:57.479 INFO 32640 --- [taskScheduler-7] com.battcn.task.SpringTaskDemo : scheduled2 每1秒執行一次:2018-05-29T17:35:57.479
2018-05-29 17:35:58.003 INFO 32640 --- [taskScheduler-4] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:58.003
2018-05-29 17:35:59.001 INFO 32640 --- [taskScheduler-5] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:35:59.001
2018-05-29 17:36:00.002 INFO 32640 --- [taskScheduler-6] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:36:00.002
2018-05-29 17:36:00.480 INFO 32640 --- [taskScheduler-7] com.battcn.task.SpringTaskDemo : scheduled2 每1秒執行一次:2018-05-29T17:36:00.480
2018-05-29 17:36:01.001 INFO 32640 --- [taskScheduler-8] com.battcn.task.SpringTaskDemo : scheduled1 每1秒執行一次:2018-05-29T17:36:01.001
2018-05-29 17:36:01.470 INFO 32640 --- [taskScheduler-9] com.battcn.task.SpringTaskDemo : scheduled3 上次執行完畢后隔3秒繼續執行:2018-05-29T17:36:01.470
目前很多大佬都寫過關于?SpringBoot?的教程了,如有雷同,請多多包涵,本教程基于最新的?spring-boot-starter-parent:2.0.2.RELEASE
編寫,包括新版本的特性都會一起介紹…
本文的重點是你有沒有收獲與成長,其余的都不重要,希望讀者們能謹記這一點。同時我經過多年的收藏目前也算收集到了一套完整的學習資料,包括但不限于:分布式架構、高可擴展、高性能、高并發、Jvm性能調優、Spring,MyBatis,Nginx源碼分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多個知識點高級進階干貨,希望對想成為架構師的朋友有一定的參考和幫助
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。