spring boot 1.5.4 定時任務和異步調用(十)

1??????Spring Boot定時任務和異步調用

我們在編寫Spring Boot應用中經常會遇到這樣的場景,比如:我需要定時地發送一些短信、郵件之類的操作,也可能會定時地檢查和監控一些標志、參數等。


spring boot定時任務spring-boot-jsp項目源碼:

碼云地址:https://git.oschina.net/wyait/springboot1.5.4.git

github地址https://github.com/wyait/spring-boot-1.5.4.git


?

1.1??創建定時任務

Spring Boot中編寫定時任務是非常簡單的事,下面通過實例介紹如何在Spring Boot中創建定時任務,實現每過5秒輸出一下當前時間。

?

1,在Spring Boot的主類中加入@EnableScheduling注解,啟用定時任務的配置

//?這是一個配置Spring的配置類

@Configuration

// @SpringBootApplicationSpring Boot項目的核心注解,主要目的是開啟自動配置。

@SpringBootApplication

@EnableScheduling//開啟定時任務

public class DemoApplication {

?

?? publicstatic void main(String[] args) {

????? //啟動spring boot應用

????? SpringApplicationsa = new SpringApplication(DemoApplication.class);

????? //禁用devTools熱部署

????? System.setProperty("spring.devtools.restart.enabled","false");

????? //禁用命令行更改application.properties屬性

????? sa.setAddCommandLineProperties(false);

????? sa.run(args);

?? }

}

2,創建定時任務實現類:

@Component

public class ScheduledTasks {

??? private static final SimpleDateFormatdateFormat = new SimpleDateFormat("HH:mm:ss");

???

??? @Scheduled(fixedRate = 5000)

??? public void reportCurrentTime() {

??????? System.out.println("現在時間:" +dateFormat.format(new Date()));

??? }

}

3運行程序,控制臺中可以看到類似如下輸出,定時任務開始正常運作了

wKioL1nLTe_Qy7HxAAAnZc6IRRA602.png

關于上述的簡單入門示例也可以參見官方的Scheduling Taskshttps://spring.io/guides/gs/scheduling-tasks/

?

1.2??@Scheduled詳解

在上面的入門例子中,使用了@Scheduled(fixedRate = 5000)注解來定義每過5秒執行的任務,對于@Scheduled的使用可以總結如下幾種方式:

  • @Scheduled(fixedRate ? ? = 5000):上一次開始執行時間點之后5秒再執行

  • @Scheduled(fixedDelay ? ? = 5000):上一次執行完畢時間點之后5秒再執行

  • @Scheduled(initialDelay=1000, ? ? fixedRate=5000):第一次延遲1秒后執行,之后按fixedRate的規則每5秒執行一次

  • @Scheduled(cron="*/5 ? ? * * * * *"):通過cron表達式定義規則

1.3??異步調用

什么是“異步調用”?

?

“異步調用”對應的是“同步調用”,同步調用指程序按照定義順序依次執行,每一行程序都必須等待上一行程序執行完成之后才能執行;異步調用指程序在順序執行時,不等待異步調用的語句返回結果就執行后面的程序。

1.3.1?????同步調用

1,下面通過一個簡單示例來直觀的理解什么是同步調用:

@Component

public class Task {

??? public static Random random =new Random();

??? public void doTaskOne() throws Exception {

??????? System.out.println("開始做任務一");

??????? long start =System.currentTimeMillis();

??????? Thread.sleep(random.nextInt(10000));

??????? long end = System.currentTimeMillis();

??????? System.out.println("完成任務一,耗時:" + (end - start) + "毫秒");

??? }

??? public void doTaskTwo() throws Exception {

??????? System.out.println("開始做任務二");

??????? long start =System.currentTimeMillis();

??????? Thread.sleep(random.nextInt(10000));

??????? long end = System.currentTimeMillis();

??????? System.out.println("完成任務二,耗時:" + (end - start) + "毫秒");

??? }

??? public void doTaskThree() throws Exception{

???? ???System.out.println("開始做任務三");

??????? long start =System.currentTimeMillis();

??????? Thread.sleep(random.nextInt(10000));

??????? long end = System.currentTimeMillis();

??????? System.out.println("完成任務三,耗時:" + (end - start) + "毫秒");

??? }

}

2Controller中新增方法:

@Autowired

?? privateTask task;

?

?? @ApiIgnore

?? @RequestMapping("/test")

?? publicvoid getTest() {

????? try{

??????? task.doTaskOne();

??????? task.doTaskTwo();

??????? task.doTaskThree();

????? }catch (Exception e) {

??????? //TODO Auto-generated catch block

??????? e.printStackTrace();

????? }

?? }

3,啟動,訪問:

開始做任務一

完成任務一,耗時:4910毫秒

開始做任務二

完成任務二,耗時:5104毫秒

開始做任務三

完成任務三,耗時:2853毫秒

任務一、任務二、任務三順序的執行完了,換言之doTaskOnedoTaskTwodoTaskThree三個函數順序的執行完成。

1.3.2?????異步調用

上述的同步調用雖然順利的執行完了三個任務,但是可以看到執行時間比較長,若這三個任務本身之間不存在依賴關系,可以并發執行的話,同步調用在執行效率方面就比較差,可以考慮通過異步調用的方式來并發執行。

?

Spring Boot中,我們只需要通過使用@Async注解就能簡單的將原來的同步函數變為異步函數,Task類改在為如下模式:

@Component

public class Task {

??? @Async

??? public void doTaskOne() throws Exception {

?? ?????//?同上內容,省略

??? }

??? @Async

??? public void doTaskTwo() throws Exception {

??????? //?同上內容,省略

??? }

??? @Async

??? public void doTaskThree() throws Exception{

??????? //?同上內容,省略

??? }

}

為了讓@Async注解能夠生效,還需要在SpringBoot的主程序中配置@EnableAsync@EnableScheduling直接替換掉),如下所示:

//?這是一個配置Spring的配置類

@Configuration

// @SpringBootApplicationSpring Boot項目的核心注解,主要目的是開啟自動配置。

@SpringBootApplication

//@EnableScheduling//開啟定時任務

@EnableAsync

public class DemoApplication {

?

?? publicstatic void main(String[] args) {

????? //啟動spring boot應用

????? SpringApplicationsa = new SpringApplication(DemoApplication.class);

????? //禁用devTools熱部署

????? System.setProperty("spring.devtools.restart.enabled","false");

????? //禁用命令行更改application.properties屬性

????? sa.setAddCommandLineProperties(false);

????? sa.run(args);

?? }

}

啟動,結果:

此時可以反復執行單元測試,您可能會遇到各種不同的結果,比如:

?

  • 沒有任何任務相關的輸出

  • 有部分任務相關的輸出

  • 亂序的任務相關的輸出

?

原因是目前doTaskOnedoTaskTwodoTaskThree三個函數的時候已經是異步執行了。主程序在異步調用之后,主程序并不會理會這三個函數是否執行完成了,由于沒有其他需要執行的內容,所以程序就自動結束了,導致了不完整或是沒有輸出任務相關內容的情況。

?

注:?@Async所修飾的函數不要定義為static類型,這樣異步調用不會生效

1.3.3?????異步回調

為了讓doTaskOnedoTaskTwodoTaskThree能正常結束,假設我們需要統計一下三個任務并發執行共耗時多少,這就需要等到上述三個函數都完成調動之后記錄時間,并計算結果。

?

那么我們如何判斷上述三個異步調用是否已經執行完成呢?我們需要使用Future<T>來返回異步調用的結果,就像如下方式改造doTaskOne函數:

@Async

?? publicFuture<String> doTaskOne() throws Exception {

????? System.out.println("開始做任務一");

????? longstart = System.currentTimeMillis();

????? Thread.sleep(random.nextInt(10000));

????? longend = System.currentTimeMillis();

????? System.out.println("完成任務一,耗時:" + (end - start) + "毫秒");

????? returnnew AsyncResult<>("任務一完成");

?? }

按照如上方式改造一下其他兩個異步函數之后,下面我們改造一下Controller中方法,在等待完成三個異步調用之后來做一些其他事情。

@ApiIgnore

?? @RequestMapping("/test1")

?? publicvoid getTest1() {

????? try{

??????? longstart = System.currentTimeMillis();

??????? Future<String>task1 = task.doTaskOne();

??????? Future<String>task2 = task.doTaskTwo();

??????? Future<String>task3 = task.doTaskThree();

??????? while(true) {

?????????? if(task1.isDone() && task2.isDone() && task3.isDone()) {

????????????? //三個任務都調用完成,退出循環等待

????????????? break;

?????????? }

?????????? Thread.sleep(1000);

??????? }

??????? longend = System.currentTimeMillis();

??????? System.out.println("任務全部完成,總耗時:" + (end - start) + "毫秒");

????? }catch (Exception e) {

??????? e.printStackTrace();

????? }

?? }

看看我們做了哪些改變:

  • 在測試用例一開始記錄開始時間

  • 在調用三個異步函數的時候,返回Future<String>類型的結果對象

  • 在調用完三個異步函數之后,開啟一個循環,根據返回的Future<String>對象來判斷三個異步函數是否都結束了。若都結束,就結束循環;若沒有都結束,就等1秒后再判斷。

  • 跳出循環之后,根據結束時間 - 開始時間,計算出三個任務并發執行的總耗時。

執行一下上述的單元測試,可以看到如下結果:

wKiom1nLTjrhvulDAAATVOws5-U026.png

可以看到,通過異步調用,讓任務一、二、三并發執行,有效的減少了程序的總運行時間。

?


本文轉自 wyait 51CTO博客,原文鏈接:http://blog.51cto.com/wyait/1969164,如需轉載請自行聯系原作者

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539721.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539721.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539721.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ORA-04063: view DAILY.TMP_TBX_100_0_S4 有錯誤

執行&#xff1a; CREATE TABLE TMP_TBX_100_0_S3 AS SELECT t.* FROM (select t1.*,NULL AS sdate, NULL AS report_id from TMP_TBX_100_0_S4_1 t1 union all select t2.* from TMP_TBX_100_0_S4_2 t2) t 報錯&#xff1a; ORA-00955: name is already used by an exis…

MySQL左連接還有過濾條件_MySQL左連接問題,右表做篩選,左表列依然在?

問 題原料兩張表&#xff0c;一張user表&#xff0c;一張user_log表(這個例子舉的不好)CREATE TABLE user (id int(11) NOT NULL AUTO_INCREMENT,name varchar(20) DEFAULT NULL,PRIMARY KEY (id)) ENGINEInnoDB DEFAULT CHARSETutf8;CREATE TABLE user_log (id int(10) NOT NU…

2017工作總結

靜兒總結自己的職業生涯分為三個階段。第一個階段為期十年&#xff0c;是純技術階段&#xff0c;是人生的積累期。第二個階段是管理階段&#xff0c;是綜合能力整合期。第三個階段是突破階段&#xff0c;打造自己獨特的核心競爭力。 第一階段 剛畢業的同學可能會覺得技術高大上…

批量刪除table或view

一個個刪太費時了。一個簡單可行的方法。 思路&#xff1a; 找出要刪除的表名/視圖名&#xff0c;然后拼接刪除sql&#xff0c;執行。 批量刪除表&#xff1a; 1、找出要刪除的表名select table_name from user_tables where table_name like S1MSGLATENCY_2016032%;2、復制這…

編譯安裝mysql5.5.39_編譯安裝MySQL5.5

防偽碼&#xff1a;沒有相當程度的孤獨是不可能有內心的平和。1、測試環境主機名IP系統MySQL版本MySQL-00192.168.10.23CentOS release 6.9 (Final)5.5.562、部署2.1 卸載之前版本rpm -qa|grep mysqlrpm -e --nodeps mysql-libs-5.1.73-8.el6_8.x86_642.2 安裝依賴包和cmakeyum…

你真的了解iOS怎么取屬性的嗎?

你真的了解iOS怎么取屬性的嗎&#xff1f; 本文來自CocoaChina粉絲FlyOceanFish投稿如果iOS中談到取屬性&#xff0c;相信大家都會夸夸其談&#xff0c;不就是get方法嗎&#xff1f;或者大談kvc取屬性的機制。不得不說這些也是對的。這時大家可能就疑惑了&#xff0c;那你還要說…

Oracle表的并行度

查看dba_tables數據字典時&#xff0c;可以發現有“DEGREE”字段&#xff0c;這個字段表示的就是數據表的并行度。這個參數的設置&#xff0c;關系著數據庫的I/O&#xff0c;以及sql的執行效率。并行度的優點就是能夠最大限度的利用機器的多個cpu資源&#xff0c;是多個cpu同時…

mysql 臨時表 限制_Mysql臨時表

當你創建臨時表的時候&#xff0c;你可以使用temporary關鍵字。如&#xff1a;create temporary table tmp_table(name varchar(10) not null,passwd char(6) not null)‘或CREATE TEMPORARY TABLE IF NOT EXISTS sp_output_tmp ENGINE MEMORY SELECT …from … where IDcurre…

10年老兵給程序員的10條建議!

2019獨角獸企業重金招聘Python工程師標準>>> 程序員雖然薪資待遇好&#xff0c;但是也得付出努力&#xff0c;技術好才行。特別是對于剛剛進入編程工作的新手程序員和正在學習編程的同學來說&#xff0c;一寫代碼就報錯&#xff0c;出bug。作為一個工作了10年的老兵…

視圖和表的區別和聯系

區別&#xff1a; 1、視圖是已經編譯好的sql語句。而表不是 2、視圖沒有實際的物理記錄。而表有。 3、表是內容&#xff0c;視圖是窗口 4、表只用物理空間而視圖不占用物理空間&#xff0c;視圖只是邏輯概念的存在&#xff0c;表可以及時四對它進行修改&#xf…

mysql binlog日志三種格式_MySQL binlog三種格式詳細介紹

查看當前數據庫binlog日志格式&#xff1a;show global variables like %binlog_format%;一、三種格式介紹1.1 STATEMENT該格式下每一條會修改數據的sql都會記錄在binlog中&#xff1b;優點&#xff1a;不需要記錄每一行的變化&#xff0c;減少了binlog日志量&#xff0c;節約了…

2017阿里技術年度精選(全)

2019獨角獸企業重金招聘Python工程師標準>>> 2017年&#xff0c;在技術發展的歷史上&#xff0c;一定是個特別的一年&#xff1a;柯潔與AlphaGo的驚世大戰&#xff0c;無人咖啡店開放體驗&#xff0c;AI設計師“魯班”橫空出世、三年投入千億的達摩院正式成立…… 這…

查詢Oracle正在執行的sql語句,鎖表,解鎖

原文出處&#xff1a;http://blog.csdn.net/jlds123/article/details/6572559 ----------------------- --查詢Oracle正在執行的sql語句及執行該語句的用戶 [sql] view plaincopy SELECT b.sid oracleID, b.username 登錄Oracle用戶名, b.serial#, …

xampp for mac mysql_xampp for mac下載-Xampp Mac版下載 V7.3.2-PC6蘋果網

Xampp for mac是目前時下最流行的PHP開發環境&#xff0c;XAMPP是完全免費且易于安裝的Apache發行版&#xff0c;其中包含MySQL、PHP和Perl。XAMPP開放源碼包的設置讓安裝和使用出奇容易。整合型的Apache套件。XAMPP包括Apache、MySQL、PHP、PERL&#xff0c;直接解壓縮&#x…

15.2. important

<para><important>Text goes here.</important></para>重要Text goes here.原文出處&#xff1a;Netkiller 系列 手札 本文作者&#xff1a;陳景峯 轉載請與作者聯系&#xff0c;同時請務必標明文章原始出處和作者信息及本聲明。

查看表的創建時間

select OWNER,OBJECT_NAME,CREATED from dba_objects where OBJECT_NAME表名 CREATED 是表的創建時間 查詢 dba_objects 表需要dba權限

linux python2.7 scipy_scipy.sparse.linalg.sp為Linux系統上的大型稀疏矩陣解決了令人驚訝的行為...

我正在計算一個線性系統Ax b的解決方案&#xff0c;其中A具有一個大的(通常200,000行和相關的密集矩陣的列)稀疏矩陣和ba稀疏矩陣&#xff0c;大約100列。當我在Windows系統上運行代碼(Python2.7&#xff0c;scipy0.14.0)時&#xff0c;以下命令fromscipy.sparse.linalgimport…

簡簡單單的代碼讓你輕松學會 動態代理

原文出處&#xff1a;http://weixiaolu.iteye.com/blog/1477774 -------------------------------------------------------------------------- 簡簡單單的代碼讓你輕松學會動態代理 前言&#xff1a; 最近一直在分析hadoop的RPC機制。在hadoop中&#xff0c;DataNode和Na…

python變量和字符_Python變量和字符串

我需要知道Python中的變量是字符串(名稱)還是數字。我想檢查圖的度數&#xff0c;但是我需要知道“I”迭代器是字符串內部的一個數字還是字符串內的一個名稱&#xff0c;在末尾顯示了圖的度數。在這個代碼有什么問題嗎&#xff1f;在import csv, sysimport networkx as nxdef m…

Adobe軟件打開后設置默認頁面方式和默認鼠標方式

PDF文件打開后是默認顯示&#xff0c;與顯示器比例不協調&#xff0c;或大或小&#xff0c;總是需要手動調節閱讀方式&#xff0c;解決方法如下&#xff1a; Adobe軟件中可以設置默認頁面方式&#xff0c;具體步驟如下&#xff1a; 編輯 (Edit)-首選項(Preferences)-輔助工具…