Spring Boot 的定时工作:
第一种:把参数配置到.properties文件中:
代码:
package com.accord.task; import java.text.SimpleDateFormat;import java.util.Date; import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component; /** * 从配置文件加载工作信息 * @author 王久印 */@Componentpublic class ScheduledTask { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); //@Scheduled(fixedDelayString = "${jobs.fixedDelay}") @Scheduled(fixedDelayString = "2000") public void getTask1() { System.out.println("工作1,从配置文件加载工作信息,以后工夫:" + dateFormat.format(new Date())); } @Scheduled(cron = "${jobs.cron}") public void getTask2() { System.out.println("工作2,从配置文件加载工作信息,以后工夫:" + dateFormat.format(new Date())); }}
application.properties文件:
jobs.fixedDelay=5000jobs.cron=0/5 * * * * ?
SpringBootCron2Application.java中:
package com.accord; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication@EnableSchedulingpublic class SpringBootCron2Application { public static void main(String[] args) { SpringApplication.run(SpringBootCron2Application.class, args); }}
Spring Boot 根底就不介绍了,举荐看这个收费教程:
https://github.com/javastacks/spring-boot-best-practice
注:@EnableScheduling 这个肯定要加上;否则,不会定时启动工作!
@Scheduled中的参数阐明:
@Scheduled(fixedRate=2000)
:上一次开始执行工夫点后2秒再次执行;@Scheduled(fixedDelay=2000)
:上一次执行结束工夫点后2秒再次执行;@Scheduled(initialDelay=1000, fixedDelay=2000)
:第一次提早1秒执行,而后在上一次执行结束工夫点后2秒再次执行;@Scheduled(cron="* * * * * ?")
:按cron规定执行。
第二种定时工作:单线程和多线程
1、创立定时工作:
package com.accord.task; import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component; /** * 构建执行定时工作 * @author 王久印 * TODO */@Componentpublic class ScheduledTask2 { private Logger logger = LoggerFactory.getLogger(ScheduledTask2.class); private int fixedDelayCount = 1; private int fixedRateCount = 1; private int initialDelayCount = 1; private int cronCount = 1; @Scheduled(fixedDelay = 5000) //fixedDelay = 5000示意以后办法执行结束5000ms后,Spring scheduling会再次调用该办法 public void testFixDelay() { logger.info("===fixedDelay: 第{}次执行办法", fixedDelayCount++); } @Scheduled(fixedRate = 5000) //fixedRate = 5000示意以后办法开始执行5000ms后,Spring scheduling会再次调用该办法 public void testFixedRate() { logger.info("===fixedRate: 第{}次执行办法", fixedRateCount++); } @Scheduled(initialDelay = 1000, fixedRate = 5000) //initialDelay = 1000示意提早1000ms执行第一次工作 public void testInitialDelay() { logger.info("===initialDelay: 第{}次执行办法", initialDelayCount++); } @Scheduled(cron = "0 0/1 * * * ?") //cron承受cron表达式,依据cron表达式确定定时规定 public void testCron() { logger.info("===initialDelay: 第{}次执行办法", cronCount++); } }
应用 @Scheduled来创立定时工作 这个注解用来标注一个定时工作办法。
通过看 @Scheduled源码能够看出它反对多种参数:
- cron:cron表达式,指定工作在特定工夫执行;
- fixedDelay:示意上一次工作执行实现后多久再次执行,参数类型为long,单位ms;
- fixedDelayString:与fixedDelay含意一样,只是参数类型变为String;
- fixedRate:示意按肯定的频率执行工作,参数类型为long,单位ms;
- fixedRateString: 与fixedRate的含意一样,只是将参数类型变为String;
- initialDelay:示意提早多久再第一次执行工作,参数类型为long,单位ms;
- initialDelayString:与initialDelay的含意一样,只是将参数类型变为String;
- zone:时区,默认为以后时区,个别没有用到。
2、开启定时工作:
package com.accord; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication@EnableSchedulingpublic class SpringBootCron2Application { public static void main(String[] args) { SpringApplication.run(SpringBootCron2Application.class, args); }}
注:这里的 @EnableScheduling 注解,它的作用是发现注解 @Scheduled的工作并由后盾执行。没有它的话将无奈执行定时工作。
援用官网文档原文:
@EnableScheduling ensures that a background task executor is created. Without it, nothing gets scheduled.
3、执行后果(单线程)
就实现了一个简略的定时任务模型,上面执行springBoot察看执行后果:
从控制台输出的后果中咱们能够看出所有的定时工作都是在同一个线程池用同一个线程来解决的,那么咱们如何来并发的解决各定时工作呢,请持续向下看。
4、多线程解决定时工作:
看到控制台输入的后果,所有的定时工作都是通过一个线程来解决的,我预计是在定时工作的配置中设定了一个SingleThreadScheduledExecutor
,于是我看了源码,从ScheduledAnnotationBeanPostProcessor
类开始一路找上来。果然,在ScheduledTaskRegistrar
(定时工作注册类)中的ScheduleTasks
中又这样一段判断:
if (this.taskScheduler == null) { this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}
这就阐明如果taskScheduler
为空,那么就给定时工作做了一个单线程的线程池,正好在这个类中还有一个设置taskScheduler
的办法:
public void setScheduler(Object scheduler) { Assert.notNull(scheduler, "Scheduler object must not be null"); if (scheduler instanceof TaskScheduler) { this.taskScheduler = (TaskScheduler) scheduler; } else if (scheduler instanceof ScheduledExecutorService) { this.taskScheduler = new ConcurrentTaskScheduler(((ScheduledExecutorService) scheduler)); } else { throw new IllegalArgumentException("Unsupported scheduler type: " + scheduler.getClass()); }}
这样问题就很简略了,咱们只需用调用这个办法显式的设置一个ScheduledExecutorService
就能够达到并发的成果了。咱们要做的仅仅是实现SchedulingConfigurer
接口,重写configureTasks
办法就OK了;
package com.accord.task; import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.config.ScheduledTaskRegistrar; import java.util.concurrent.Executors; /** * 多线程执行定时工作 * @author 王久印 */@Configuration//所有的定时工作都放在一个线程池中,定时工作启动时应用不同都线程。public class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { //设定一个长度10的定时工作线程池 taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10)); }}
5、执行后果(并发)
通过控制台输入的后果看出每个定时工作都是在通过不同的线程来解决了。
起源:wangjiuyin.blog.csdn.net/article/details/79411952
近期热文举荐:
1.1,000+ 道 Java面试题及答案整顿(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!