我们会经常遇到需要做定时任务的需求,可能会遇到多任务调度的场景。那么为了方便理解和维护,会对定时任务进行分类,创建不同的类与不同的方法。每个类对应不同的业务,每个类的方法对应不同的逻辑功能。
一下模拟两个类,每个类有两个定时调度方法:
一、首先开启定时任务
在启动类添加
@EnableScheduling
二、模拟报警业务定时任务AlarmCrontab
package xyz.hashdog.job;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author th
* @description: 定时任务测试
* @projectName AlarmCrontab
* @date 2020/2/1223:07
*/
@Component
@Slf4j
public class AlarmCrontab {
@Scheduled(cron = "*/5 * * * * ?")
public void test1() throws InterruptedException {
try {
for (int i =0;i<=10;i++){
System.out.println("AlarmCrontab:test1执行:"+i);
Thread.sleep(2000);
}
} catch (Exception e) {
log.error("AlarmCrontab:test1执行出错", e);
}
log.warn("AlarmCrontab:test1执行完成");
}
@Scheduled(cron = "*/5 * * * * ?")
public void test2() {
try {
for (int i =0;i<=10;i++){
System.out.println("AlarmCrontab:test2执行:"+i);
Thread.sleep(2000);
}
} catch (Exception e) {
log.error("AlarmCrontab:test2执行出错", e);
}
log.warn("AlarmCrontab:test2执行完成");
}
}
三、模拟文档业务定时任务DocCrontab
package xyz.hashdog.job;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
/**
* @author th
* @description: 定时任务测试
* @projectName DocCrontab
* @date 2020/2/1223:07
*/
@Component
@Slf4j
class DocCrontab {
@Scheduled(cron = "*/5 * * * * ?")
public void test1() throws InterruptedException {
try {
for (int i =0;i<=10;i++){
System.out.println("DocCrontab:test1执行:"+i);
Thread.sleep(2000);
}
} catch (Exception e) {
log.error("DocCrontab:test1执行出错", e);
}
log.warn("DocCrontab:test1执行完成");
}
@Scheduled(cron = "*/5 * * * * ?")
public void test2() {
try {
for (int i =0;i<=10;i++){
System.out.println("DocCrontab:test2执行:"+i);
Thread.sleep(2000);
}
} catch (Exception e) {
log.error("DocCrontab:test2执行", e);
}
log.warn("DocCrontab:test2执行完成");
}
}
四、执行发现,两个类的四个方法是一次执行的
因为Scheduled是单线程的
五、多线程异步执行
因为单线程同步执行,效率低
1.可以考虑使用@Async注解,这四个方法会异步执行,但是会导致同一个方法的上个任务未执行完,下个任务又开始了
@Async注解详细可以参考:https://blog.csdn.net/corleone_4ever/article/details/104292363
2.那么又想让四个函数异步同时执行,又不影响同一个方法的线程安全问题,那么可以使用加锁的形式
可以参考:https://blog.csdn.net/corleone_4ever/article/details/104289231
3.这里使用配置线程池的形式,更简单
添加一个config配置类
线程池配置可参考:https://blog.csdn.net/corleone_4ever/article/details/104292423
package xyz.hashdog.datasynchronism.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* @author th
* @description: Job相关配置
* @projectName hashdog-ds
* @date 2020/2/1311:27
*/
@Configuration
public class JobConfig {
/**
*任务调度线程池配置
* @author: th
* @date: 2020/2/13 11:53
* @param
* @return: org.springframework.scheduling.TaskScheduler
*/
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(50);
return taskScheduler;
}
}
六、测试多任务同时调度
那么可以看到两个类的四个方法同时进行调度,并且不会存在单方法的线程安全问题