一、背景
再次进行java小白的学习成长喽。
平时的日常工作主要就是接口+脚本,那么问题来了,java是如何将定时任务跑起来的。
查找资料了解到java本身有一套类似于linux的crontab的功能,并且还支持秒级控制。crontab只支持到分钟,之前php脚本只能用while(true)+sleep()的方式实现。
好,进入今天的实践吧~
二、导入核心包
在pom.xml将加入下面内容
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
三、开启定时任务的配置
程序的总入口DemoApplication,增加@EnableScheduling注解,开启定时任务的配置
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
四、定时脚本处理
新建CronTab.java,代码如下:
package com.example.demo.controller;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public class CronTab {
private static Logger logger = LoggerFactory.getLogger(CronTab.class);
@Scheduled(cron = "0/5 * * * * *")
public void testLog() {
logger.info("===testLog开启===" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("===testLog结束===" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
打印日志:
2020-05-31 19:41:45.000 INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab : ===testLog开启===2020-05-31 19:41:45
2020-05-31 19:41:51.001 INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab : ===testLog结束===2020-05-31 19:41:51
2020-05-31 19:41:51.001 INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab : ===testLog开启===2020-05-31 19:41:51
2020-05-31 19:41:57.002 INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab : ===testLog结束===2020-05-31 19:41:57
2020-05-31 19:41:57.002 INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab : ===testLog开启===2020-05-31 19:41:57
嗯,看着还挺符合预期的,每隔5s运行一次。
但是把testLog复制了几次,多加了几个定时任务:
emmm 执行的很有序,一个完成另外一个在开始,但是很明显,这不是我们想要的...
原因是定时任务默认都是使用单线程执行的。
那么接下来我们开始搞多进程处理定时任务
五、开启多进程
增加CronConfig.java
package com.example.demo.controller;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
public class CronConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
// 设置scheduler执行线程为3个
scheduler.setPoolSize(3);
return scheduler;
}
}
再来看下效果:
嗯,看起来很完美。那我接着把定时任务设置的凌乱点,有的5s执行一次,有的3s执行一次,再来看下效果:
emmmm 经过初次实践,将进程数设置多点和时间凌乱点都会导致不太理想,这个还需继续查询一下应该如何处理,挖个坑待填上吧(ps:这个多进程的方案是从网上找的,不确定是不是我哪里写的有问题)
六、定时时间配置
关于定时时间的设置方式如下:
这四种的具体说明:
1、@Scheduled(fixedDelay = 1000)
fixedDelay控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。
2、@Scheduled(fixedRate = 5000)
fixedRate是按照一定的速率执行,是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行。
3、@Scheduled(cron="0/5 * * * * ? ")
cron表达式可以定制化执行任务,但是执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起。
CronTrigger配置完整格式为: [秒] [分] [小时] [日] [月] [周] [年]
4、@Scheduled(initialDelay = 50000,fixedRate = 6000)
这个定时器就是在fixedRate的基础上加了一个initialDelay = 10000 意思就是在容器启动后,延迟10秒后再执行一次定时器,以后每15秒再执行一次该定时器。
七、后记
哈,还有多进程的问题没完全解决,并没有到写后记的时候,待我填坑完成再补写后记吧