1、Spring Task
1.1、同一线程调度
(1)在主程序入口处添加如下注解
//@SpringBootApplication
@EnableScheduling
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
如上代码所示:@EnableScheduling的注解
(2)在对应的测试方法中添加对应的注解
@Scheduled(fixedRate = 2000)
public void test() {
Thread thread = Thread.currentThread();
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println("调度测试:" + "test----" + format.format(new Date()) + "------>" + thread.getId());
}
@Scheduled(fixedRate = 2000)
public void test1() {
Thread thread = Thread.currentThread();
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println("调度测试:" + "test1----" + format.format(new Date()) + "----->" + thread.getId());
}
如上代码所示:@Scheduled(fixedRate=2000),含义为每两秒调用一次,如下所示的日志打印所示:
调度测试:test----2018-43-24 16:43:56------>27
调度测试:test1----2018-43-24 16:43:56----->27
调度测试:test----2018-43-24 16:43:58------>27
调度测试:test1----2018-43-24 16:43:58----->27
调度测试:test----2018-44-24 16:44:00------>27
调度测试:test1----2018-44-24 16:44:00----->27
调度测试:test----2018-44-24 16:44:02------>27
调度测试:test1----2018-44-24 16:44:02----->27
调度测试:test----2018-44-24 16:44:04------>27
调度测试:test1----2018-44-24 16:44:04——>27
对于注解中的参数解释:
-
fixedRate:定义一个按一定频率执行的定时任务
-
fixedDelay: 定义一个按一定频率执行的定时任务,与上面不同的是,改属性可以配合initiaDelay, 定义该任务延迟执行时间
-
cron : 通过表达式来配置任务执行时间(关于cron的介绍请看下面的讲解)
但是如上面代码所示打印出来的调度,可以看出来,两个调度使用的是同一个线程,这个在少量使用的过程中是没有问题的,当随着调度的增多,如果出现线程中某一个调度出错,在同一个线程中就会导致线程卡死,其他调度都不会自动调度,所以下面将介绍通过不同的线程来调用。
1.2、不同线程调度
在springboot框架中,已经进行了进行,因此需要新建了一个配置类如下
@Configuration
@EnableAsync
public class AsyncConfig {
//这里标准的话使用@Value来获取配置文件中的值,这里只为测试,就直接硬编码
private int corePoolSize = 10;
private int maxPoolSize = 200;
private int queueCapacity = 10;
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.initialize();
return executor;
}
}
解释:
@Configuration 提示这个类为配置工具类
@EnableAsync 开启异步事件的支持
然后在对应的调用的方法中添加@Async注解就可以了,代码如下:
@Scheduled(fixedRate = 2000)
@Async
public void test() {
Thread thread = Thread.currentThread();
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println("调度测试:" + "test----" + format.format(new Date()) + "------>" + thread.getId());
}
@Scheduled(fixedRate = 2000)
@Async
public void test1() {
Thread thread = Thread.currentThread();
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println("调度测试:" + "test1----" + format.format(new Date()) + "----->" + thread.getId());
}
然后运行程序,打印的日志如下所示:
调度测试:test----2018-11-24 17:11:52------>53
调度测试:test1----2018-11-24 17:11:52----->54
调度测试:test----2018-11-24 17:11:54------>55
调度测试:test1----2018-11-24 17:11:54----->56
调度测试:test----2018-11-24 17:11:56------>57
调度测试:test1----2018-11-24 17:11:56----->58
调度测试:test----2018-11-24 17:11:58------>59
调度测试:test1----2018-11-24 17:11:58----->60
调度测试:test1----2018-12-24 17:12:00----->28
调度测试:test----2018-12-24 17:12:00------>29
从上面的日志可以看出来,两个调用方法对应的线程的id是不一样的,这样就可以多线程同时进行了。
2、使用Quartz
springboot整合Quartz
如果springboot是2.0.0版本以上的需要添加如下的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
如果是1.5.9版本的添加如下的依赖:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
创建任务类:
public class TestQuartz extends QuartzJobBean {
/**
* 执行定时任务
* @param jobExecutionContext
* @throws JobExecutionException
*/
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("quartz task "+new Date());
}
}
然后创建配置类:
@Configuration
public class QuartzConfig {
@Bean
public JobDetail teatQuartzDetail(){
return JobBuilder.newJob(TestQuartz.class).withIdentity("testQuartz").storeDurably().build(); }
@Bean
public Trigger testQuartzTrigger(){
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) //设置时间周期单位秒
.repeatForever();
return TriggerBuilder.newTrigger().forJob(teatQuartzDetail())
.withIdentity("testQuartz")
.withSchedule(scheduleBuilder)
.build();
}
}
运行测试:
cron的详解:
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素
-
秒(0~59)
-
分钟(0~59)
-
3 小时(0~23)
-
4 天(0~31)
-
5 月(0~11)
-
6 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
-
年份(1970-2099)
具体的实例如下:
-
每隔5秒执行一次:/5 * ?
-
每隔1分钟执行一次:0 /1 ?
-
0 0 10,14,16 ? 每天上午10点,下午2点,4点
-
0 0/30 9-17 ? 朝九晚五工作时间内每半小时
-
0 0 12 ? * WED 表示每个星期三中午12点
-
“0 0 12 ?” 每天中午12点触发
-
“0 15 10 ? “ 每天上午10:15触发
-
“0 15 10 ?” 每天上午10:15触发
-
“0 15 10 ? *” 每天上午10:15触发
-
“0 15 10 ? 2005” 2005年的每天上午10:15触发
-
“0 14 * ?” 在每天下午2点到下午2:59期间的每1分钟触发
-
“0 0/5 14 ?” 在每天下午2点到下午2:55期间的每5分钟触发
-
“0 0/5 14,18 ?” 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
-
“0 0-5 14 ?” 在每天下午2点到下午2:05期间的每1分钟触发
-
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44触发
-
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15触发
-
“0 15 10 15 * ?” 每月15日上午10:15触发
-
“0 15 10 L * ?” 每月最后一日的上午10:15触发
-
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
-
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
-
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发