一、定时任务的理解
定时任务即系统在特定时间执行一段代码,它的场景应用非常广泛:
- 购买游戏的月卡会员后,系统每天给会员发放游戏资源。
- 管理系统定时生成报表。
- 定时清理系统垃圾。
定时任务的实现主要有以下几种方式:
1、Java自带的java.util.Timer类,这个类允许调度一个java.util.TimerTask任务。使用这种方式可以让程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
2、Quartz。这是一个功能比较强大的的调度器,可以让程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。
3、Spring3.0以后自带Spring Task,可以将它看成一个轻量级的Quartz,使用起来比 Quartz简单许多,在课程中我们使用Spring Task实现定时任务
二、入门案例
创建SpringBoot项目,在启动类开启定时任务。
也就是在启动类上方添加@EnableScheduling注解即可开启定时任务,代码如下:
编写定时任务类
启动项目,定时任务方法按照配置定时执行。
OK,果然如此,每隔2秒输出当前时间
@Scheduled写在方法上方,指定该方法定时执行。常用参数如下:
- cron:cron表达式,定义方法执行的时间规则。
- fixedDelay:任务立即执行,之后每隔多久执行一次,单位是毫秒,上一次任务结束后计算下次执行的时间。
OK,先来一个案例,代码如下:任务结束后每隔五秒执行一次
效果如下:
OK,果然如此,注意这个是任务结束后每隔五秒
initialDelay:项目启动后不马上执行定时器,根据initialDelay的值延时执行。 这里配合fixedDelay来结合测试演示一下:
OK,看运行结果也是隔了三秒才出现第一次打印时间,并且打印时间是隔六秒打印一次
三、多线程案例
Spring Task定时器默认是单线程的,如果项目中使用多个定时器,使用一个线程会造成效率低下。
比如说我们设置了两个定时任务,那么因为Spring Task是单线程,如果在第一个定时任务加了一个sleep方法,那么会等第一个方法响应后在执行第二个任务,就很浪费cpu运行时间。代码如下:
@Scheduled(cron = "* * * * * *")
public void task3() throws InterruptedException {
System.out.println(Thread.currentThread().getId()+"线程执行任务1 - "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
Thread.sleep(5000);
}
@Scheduled(cron = "* * * * * *")
public void task4() throws InterruptedException {
System.out.println(Thread.currentThread().getId()+"线程执行任务2 - "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
执行效果如下:可以看到是先执行了任务2,但是他们都要隔五秒才能运行一次,因为通过线程号可以知道这是同一个线程。
因此任务1较浪费时间,会阻塞任务2的运行。此时我们可以给SpringTask配置线程池。代码如下:
@Configuration
public class SchedulingConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 创建线程池,设置五个线程
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(4));
}
}
这样就不会出现阻塞问题了,因为两个任务不是同一个线程,接下来我们再次运行看看:
执行效果如上,确实不会影响到任务2的运行,但是如果定时任务过多,超过了配置的线程池的线程数量还是会运行错乱。
标签:Task,Spring,任务,线程,详细,定时,执行 From: https://blog.csdn.net/weixin_52496592/article/details/140966504