日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

spring boot 1.5.4 定时任务和异步调用(十)

發(fā)布時(shí)間:2025/3/8 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot 1.5.4 定时任务和异步调用(十) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1??????Spring Boot定時(shí)任務(wù)和異步調(diào)用

我們?cè)诰帉?xiě)Spring Boot應(yīng)用中經(jīng)常會(huì)遇到這樣的場(chǎng)景,比如:我需要定時(shí)地發(fā)送一些短信、郵件之類(lèi)的操作,也可能會(huì)定時(shí)地檢查和監(jiān)控一些標(biāo)志、參數(shù)等。


spring boot定時(shí)任務(wù)spring-boot-jsp項(xiàng)目源碼:

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

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


?

1.1??創(chuàng)建定時(shí)任務(wù)

Spring Boot中編寫(xiě)定時(shí)任務(wù)是非常簡(jiǎn)單的事,下面通過(guò)實(shí)例介紹如何在Spring Boot中創(chuàng)建定時(shí)任務(wù),實(shí)現(xiàn)每過(guò)5秒輸出一下當(dāng)前時(shí)間。

?

1,在Spring Boot的主類(lèi)中加入@EnableScheduling注解,啟用定時(shí)任務(wù)的配置

//?這是一個(gè)配置Spring的配置類(lèi)

@Configuration

// @SpringBootApplicationSpring Boot項(xiàng)目的核心注解,主要目的是開(kāi)啟自動(dòng)配置。

@SpringBootApplication

@EnableScheduling//開(kāi)啟定時(shí)任務(wù)

public class DemoApplication {

?

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

????? //啟動(dòng)spring boot應(yīng)用

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

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

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

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

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

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

?? }

}

2,創(chuàng)建定時(shí)任務(wù)實(shí)現(xiàn)類(lèi):

@Component

public class ScheduledTasks {

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

???

??? @Scheduled(fixedRate = 5000)

??? public void reportCurrentTime() {

??????? System.out.println("現(xiàn)在時(shí)間:" +dateFormat.format(new Date()));

??? }

}

3運(yùn)行程序,控制臺(tái)中可以看到類(lèi)似如下輸出,定時(shí)任務(wù)開(kāi)始正常運(yùn)作了

關(guān)于上述的簡(jiǎn)單入門(mén)示例也可以參見(jiàn)官方的Scheduling Taskshttps://spring.io/guides/gs/scheduling-tasks/

?

1.2??@Scheduled詳解

在上面的入門(mén)例子中,使用了@Scheduled(fixedRate = 5000)注解來(lái)定義每過(guò)5秒執(zhí)行的任務(wù),對(duì)于@Scheduled的使用可以總結(jié)如下幾種方式:

  • @Scheduled(fixedRate ? ? = 5000):上一次開(kāi)始執(zhí)行時(shí)間點(diǎn)之后5秒再執(zhí)行

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

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

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

1.3??異步調(diào)用

什么是“異步調(diào)用”?

?

“異步調(diào)用”對(duì)應(yīng)的是“同步調(diào)用”,同步調(diào)用指程序按照定義順序依次執(zhí)行,每一行程序都必須等待上一行程序執(zhí)行完成之后才能執(zhí)行;異步調(diào)用指程序在順序執(zhí)行時(shí),不等待異步調(diào)用的語(yǔ)句返回結(jié)果就執(zhí)行后面的程序。

1.3.1?????同步調(diào)用

1,下面通過(guò)一個(gè)簡(jiǎn)單示例來(lái)直觀的理解什么是同步調(diào)用:

@Component

public class Task {

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

??? public void doTaskOne() throws Exception {

??????? System.out.println("開(kāi)始做任務(wù)一");

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

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

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

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

??? }

??? public void doTaskTwo() throws Exception {

??????? System.out.println("開(kāi)始做任務(wù)二");

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

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

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

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

??? }

??? public void doTaskThree() throws Exception{

???? ???System.out.println("開(kāi)始做任務(wù)三");

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

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

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

??????? System.out.println("完成任務(wù)三,耗時(shí):" + (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,啟動(dòng),訪問(wèn):

開(kāi)始做任務(wù)一

完成任務(wù)一,耗時(shí):4910毫秒

開(kāi)始做任務(wù)二

完成任務(wù)二,耗時(shí):5104毫秒

開(kāi)始做任務(wù)三

完成任務(wù)三,耗時(shí):2853毫秒

任務(wù)一、任務(wù)二、任務(wù)三順序的執(zhí)行完了,換言之doTaskOnedoTaskTwodoTaskThree三個(gè)函數(shù)順序的執(zhí)行完成。

1.3.2?????異步調(diào)用

上述的同步調(diào)用雖然順利的執(zhí)行完了三個(gè)任務(wù),但是可以看到執(zhí)行時(shí)間比較長(zhǎng),若這三個(gè)任務(wù)本身之間不存在依賴(lài)關(guān)系,可以并發(fā)執(zhí)行的話,同步調(diào)用在執(zhí)行效率方面就比較差,可以考慮通過(guò)異步調(diào)用的方式來(lái)并發(fā)執(zhí)行。

?

Spring Boot中,我們只需要通過(guò)使用@Async注解就能簡(jiǎn)單的將原來(lái)的同步函數(shù)變?yōu)楫惒胶瘮?shù),Task類(lèi)改在為如下模式:

@Component

public class Task {

??? @Async

??? public void doTaskOne() throws Exception {

?? ?????//?同上內(nèi)容,省略

??? }

??? @Async

??? public void doTaskTwo() throws Exception {

??????? //?同上內(nèi)容,省略

??? }

??? @Async

??? public void doTaskThree() throws Exception{

??????? //?同上內(nèi)容,省略

??? }

}

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

//?這是一個(gè)配置Spring的配置類(lèi)

@Configuration

// @SpringBootApplicationSpring Boot項(xiàng)目的核心注解,主要目的是開(kāi)啟自動(dòng)配置。

@SpringBootApplication

//@EnableScheduling//開(kāi)啟定時(shí)任務(wù)

@EnableAsync

public class DemoApplication {

?

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

????? //啟動(dòng)spring boot應(yīng)用

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

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

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

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

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

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

?? }

}

啟動(dòng),結(jié)果:

此時(shí)可以反復(fù)執(zhí)行單元測(cè)試,您可能會(huì)遇到各種不同的結(jié)果,比如:

?

  • 沒(méi)有任何任務(wù)相關(guān)的輸出

  • 有部分任務(wù)相關(guān)的輸出

  • 亂序的任務(wù)相關(guān)的輸出

?

原因是目前doTaskOnedoTaskTwodoTaskThree三個(gè)函數(shù)的時(shí)候已經(jīng)是異步執(zhí)行了。主程序在異步調(diào)用之后,主程序并不會(huì)理會(huì)這三個(gè)函數(shù)是否執(zhí)行完成了,由于沒(méi)有其他需要執(zhí)行的內(nèi)容,所以程序就自動(dòng)結(jié)束了,導(dǎo)致了不完整或是沒(méi)有輸出任務(wù)相關(guān)內(nèi)容的情況。

?

注:?@Async所修飾的函數(shù)不要定義為static類(lèi)型,這樣異步調(diào)用不會(huì)生效

1.3.3?????異步回調(diào)

為了讓doTaskOnedoTaskTwodoTaskThree能正常結(jié)束,假設(shè)我們需要統(tǒng)計(jì)一下三個(gè)任務(wù)并發(fā)執(zhí)行共耗時(shí)多少,這就需要等到上述三個(gè)函數(shù)都完成調(diào)動(dòng)之后記錄時(shí)間,并計(jì)算結(jié)果。

?

那么我們?nèi)绾闻袛嗌鲜鋈齻€(gè)異步調(diào)用是否已經(jīng)執(zhí)行完成呢?我們需要使用Future<T>來(lái)返回異步調(diào)用的結(jié)果,就像如下方式改造doTaskOne函數(shù):

@Async

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

????? System.out.println("開(kāi)始做任務(wù)一");

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

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

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

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

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

?? }

按照如上方式改造一下其他兩個(gè)異步函數(shù)之后,下面我們改造一下Controller中方法,在等待完成三個(gè)異步調(diào)用之后來(lái)做一些其他事情。

@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()) {

????????????? //三個(gè)任務(wù)都調(diào)用完成,退出循環(huán)等待

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

?????????? }

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

??????? }

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

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

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

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

????? }

?? }

看看我們做了哪些改變:

  • 在測(cè)試用例一開(kāi)始記錄開(kāi)始時(shí)間

  • 在調(diào)用三個(gè)異步函數(shù)的時(shí)候,返回Future<String>類(lèi)型的結(jié)果對(duì)象

  • 在調(diào)用完三個(gè)異步函數(shù)之后,開(kāi)啟一個(gè)循環(huán),根據(jù)返回的Future<String>對(duì)象來(lái)判斷三個(gè)異步函數(shù)是否都結(jié)束了。若都結(jié)束,就結(jié)束循環(huán);若沒(méi)有都結(jié)束,就等1秒后再判斷。

  • 跳出循環(huán)之后,根據(jù)結(jié)束時(shí)間 - 開(kāi)始時(shí)間,計(jì)算出三個(gè)任務(wù)并發(fā)執(zhí)行的總耗時(shí)。

執(zhí)行一下上述的單元測(cè)試,可以看到如下結(jié)果:

可以看到,通過(guò)異步調(diào)用,讓任務(wù)一、二、三并發(fā)執(zhí)行,有效的減少了程序的總運(yùn)行時(shí)間。

?


本文轉(zhuǎn)自 wyait 51CTO博客,原文鏈接:http://blog.51cto.com/wyait/1969164,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者

總結(jié)

以上是生活随笔為你收集整理的spring boot 1.5.4 定时任务和异步调用(十)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。