常見定時任務區別
1、常見定時任務 Java自帶的java.util.Timer類
timer:配置比較麻煩,時間延後問題
timertask:不推薦
2、Quartz框架
配置更簡單
xml或者註解
3、SpringBoot使用註解方式開啓定時任務
1)啓動類裏面 @EnableScheduling開啓定時任務,自動掃描
package net.myclass;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@MapperScan("net.myclass.mapper")
@EnableScheduling
public class MyApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
2)定時任務業務類 加註解 @Component被容器掃描
3)定時執行的方法加上註解 @Scheduled(fixedRate=2000) 定期執行一次
SpringBoot常用定時任務表達式配置和在線生成器
1、cron 定時任務表達式 @Scheduled(cron="*/1 * * * * *") 表示每秒
crontab 工具 https://tool.lu/crontab/
2、fixedRate: 定時多久執行一次(上一次開始執行時間點後xx秒再次執行;)
3、fixedDelay: 上一次執行結束時間點後xx秒再次執行
4、fixedDelayString: 字符串形式,可以通過配置文件指定
package net.myclass.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class TestTask {
@Scheduled(fixedRate = 2000)//兩秒執行一次
public void sum(){
System.out.println("當前時間"+new Date());
}
}
SpringBoot2.x異步任務
用訂單/庫存系統舉例,幾千人都在買買買,一時間幾千個訂單請求到controller,然後調用service(注:service還是跟上面一樣要幾十秒),一到service,判斷是個異步方法,於是趕緊讓處理異步任務的線程過來慢慢處理就好,controller可以直接響應用戶“訂單成功”。用戶極短時間就收到響應,於是可以繼續買買買。
異步:它會把需要執行的放在一個執行隊列中,像是這種需要等待的程序,他在會在執行了之後將他排在後面,然後執行其他的任務,指導它等待結束之後,執行它的回調。
ajax請求,在這樣的請求中會有較大的時間開銷,但是這一過程中並沒有太大的資源消耗,或者說對於javascript所執行的環境來說幾乎沒有什麼資源的消耗。所以在這樣的過程中,其實主線程是空閒着的,如果不是異步的行爲,那它所做的只有一件事,那就是等待,等待請求的響應,那麼,其實在這樣的一個過程中,完全可以把主線程在等待時候的資源開放出來進行其他的操作,這就形成了異步。
1、使用場景:適用於處理log、發送郵件、短信……等
下單接口->查庫存 100
餘額校驗 150
風控用戶100
....
2、啓動類裏面使用@EnableAsync註解開啓功能,自動掃描
package net.myclass;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@MapperScan("net.myclass.mapper")
@EnableScheduling
@EnableAsync
public class MyApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
3、定義異步任務類並使用@Component標記組件被容器掃描,異步方法加上@Async
package net.myclass.task;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class AsyncTask {
@Async
public void task1() throws InterruptedException{
long begin = System.currentTimeMillis();
Thread.sleep(1000L);
long end = System.currentTimeMillis();
System.out.println("任務1耗時="+(end-begin));
}
@Async
public void task2() throws InterruptedException{
long begin = System.currentTimeMillis();
Thread.sleep(2000L);
long end = System.currentTimeMillis();
System.out.println("任務2耗時="+(end-begin));
}
@Async
public void task3() throws InterruptedException{
long begin = System.currentTimeMillis();
Thread.sleep(3000L);
long end = System.currentTimeMillis();
System.out.println("任務3耗時="+(end-begin));
}
}
注意點:
1)要把異步任務封裝到類裏面,不能直接寫到Controller
2)增加Future<String> 返回結果 AsyncResult<String>("task執行完成");
3)如果需要拿到結果 需要判斷全部的 task.isDone()
4、通過注入方式,注入到controller裏面,如果測試前後區別則改爲同步則把Async註釋掉
package net.myclass.controller;
import net.myclass.domain.JsonData;
import net.myclass.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api3/async")
public class AsyncController {
@Autowired
private AsyncTask task;
@GetMapping("async_task")
public JsonData exeTask() throws InterruptedException{
long begin=System.currentTimeMillis();
task.task1();
task.task2();
task.task3();
long end =System.currentTimeMillis();
long total=end-begin;
System.out.println("執行時間="+total);
return JsonData.buildSuccess(total);
}
}