目前市场上有很多定时任务框架,比如java自带的java.util.Timer类, 不过它配置比较麻烦,存在时间延后问题,所以不推荐,还有就是Quartz框架,它的配置更简单可以使用xml或者注解方式进行配置,如果是SpringMvc框架我们推荐使用这种。在springboot中使用定时任务直接使用它自带就行,下面我们就进行springboot定时任务以及异步任务调用的开发:
加上@EnableScheduling就能扫描根目录下所有的定时任务
package net.xdclass.base_project;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication //一个注解顶下面3个
@EnableScheduling//开启定时任务,自动扫描
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
在定时任务类上加上@Component注解,纳入容器管理,刚刚开启了定时任务扫描,那么启动之后就会扫描加了@Scheduled注解的定时任务,定期执行这个方法,写一个两秒执行一次打印的定时任务
package net.xdclass.base_project.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author sqz
* @Description: 定时任务业务类
* @date 2019/3/23 13:35
*/
@Component
public class TestTask {
@Scheduled(fixedRate = 2000)
public void sum(){
System.out.println("当前时间"+new Date());
}
}
在上面的入门例子中,使用了@Scheduled(fixedRate = 2000)
注解来定义每过2秒执行的任务,对于@Scheduled
的使用可以总结如下几种方式:
@Scheduled(fixedRate = 2000)
:上一次开始执行时间点之后2秒再执行@Scheduled(fixedDelay = 2000)
:上一次执行完毕时间点之后2秒再执行@Scheduled(initialDelay=2000, fixedRate=5000)
:第一次延迟2秒后执行,之后按fixedRate的规则每5秒执行一次@Scheduled(cron="*/5 * * * * *")
:通过cron表达式定义规则fixedDelay
没区别)fixedRate
没区别)如图所示,我定义fixedRate5秒执行一次,程序中睡4秒,这时候开始执行到下次执行就是间隔5秒,因为程序没有阻塞。
这时候我定义fixedRate2秒执行一次,但是程序4秒才执行完,也就是阻塞住了,要等到程序执行完才立即开始下一次的任务执行
这时候我定义的 fixedDelay2秒执行,但是程序执行时间是4秒,加上程序结束完再加上2秒才开始下次执行,所以间隔时间是6秒
启动类加上@EnableAsync开启异步任务
package net.xdclass.base_project;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication //一个注解顶下面3个
@EnableScheduling//开启定时任务,自动扫描
@EnableAsync//开启异步任务
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
package net.xdclass.base_project.task;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
/**
* @author sqz
* @Description: 异步任务业务类
* @date 2019/3/23 14:34
*/
@Component
public class AsyncTask {
@Async
public void task1() throws InterruptedException {
Instant begin = Instant.now();
Thread.sleep(1000);
Instant end = Instant.now();
Duration duration = Duration.between(begin,end);
System.out.println("任务1耗时:"+duration.toMillis());
}
@Async
public void task2() throws InterruptedException {
Instant begin = Instant.now();
Thread.sleep(3000);
Instant end = Instant.now();
Duration duration = Duration.between(begin,end);
System.out.println("任务2耗时:"+duration.toMillis());
}
@Async
public void task3() throws InterruptedException {
Instant begin = Instant.now();
Thread.sleep(2000);
Instant end = Instant.now();
Duration duration = Duration.between(begin,end);
System.out.println("任务3耗时:"+duration.toMillis());
}
}
这里直接注入任务类,因为他纳入了spring的管理,调用三个异步任务
package net.xdclass.base_project.controller;
import net.xdclass.base_project.domain.JsonData;
import net.xdclass.base_project.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1")
public class UserController {
@Autowired
private AsyncTask asyncTask;
@GetMapping("async_task")
public JsonData testTask() throws InterruptedException {
long begin = System.currentTimeMillis();
asyncTask.task1();
asyncTask.task2();
asyncTask.task3();
long end = System.currentTimeMillis();
long total = end -begin;
System.out.println("总耗时:"+total);
return JsonData.buildSuccess(total);
}
}
启动测试:
有返回值的任务返回结果是框架提供的Future<>,是java.util.concurrent.Future并发包下的
//获取异步结果
public Future task4() throws InterruptedException {
Instant begin = Instant.now();
Thread.sleep(3000);
Instant end = Instant.now();
Duration duration = Duration.between(begin,end);
System.out.println("任务4耗时:"+duration.toMillis());
return new AsyncResult<>("任务4");
}
public Future task5() throws InterruptedException {
Instant begin = Instant.now();
Thread.sleep(1000);
Instant end = Instant.now();
Duration duration = Duration.between(begin,end);
System.out.println("任务5耗时:"+duration.toMillis());
return new AsyncResult<>("任务5");
}
public Future task6() throws InterruptedException {
Instant begin = Instant.now();
Thread.sleep(2000);
Instant end = Instant.now();
Duration duration = Duration.between(begin,end);
System.out.println("任务6耗时:"+duration.toMillis());
return new AsyncResult<>("任务6");
}
调用三个有返回结果的任务,写一个死循环,三个任务都执行完就跳出,isDone()是Future自带的方法,判断该异步任务是否执行完成
package net.xdclass.base_project.controller;
import net.xdclass.base_project.domain.JsonData;
import net.xdclass.base_project.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Future;
@RestController
@RequestMapping("/api/v1")
public class UserController {
@Autowired
private AsyncTask asyncTask;
@GetMapping("async_task")
public JsonData testTask() throws InterruptedException {
long begin = System.currentTimeMillis();
// asyncTask.task1();
// asyncTask.task2();
// asyncTask.task3();
Future task4 = asyncTask.task4();
Future task5 = asyncTask.task5();
Future task6 = asyncTask.task6();
for (;;){
if (task4.isDone()&&task5.isDone()&&task6.isDone()){
break;
}
}
long end = System.currentTimeMillis();
long total = end -begin;
System.out.println("总耗时:"+total);
return JsonData.buildSuccess(total);
}
}
源码地址:https://gitee.com/xuxinsunqizheng/springboot_module.git