定时任务简单讲解以及使用
文章目录
- 定时任务简单讲解以及使用
- 一、JDK自带的方式
- 1.Timer
- 2.ScheduledThreadPoolExecutor
- 二、第三方
- 1.quartz
- 2.SpringTask
- 2.1演示
- 2.2实际写法
- 2.2.1注解的方式SpringBoot
- 2.2.2 springTask开启异步任务
一、JDK自带的方式
1.Timer
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask timerTask = new TimerTask(){
@Override
public void run() {
System.out.println("执行了");
}
};
}
- 一秒钟后执行
timer.schedule(timerTask,1000);
- 一秒钟后执行,然后每隔一秒执行一次
timer.schedule(timerTask,1000,1000);
- 停止
timer.cancel();
- 设定固定时间执行
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str="2021-05-09 22:30:00";
Date parse = simpleDateFormat.parse(str);
timer.schedule(timerTask,parse);
缺点:Timer是一个异步操作,但是没有线程池,不能指定固定的时间间隔一直执行这个事,比如说某个月的某一天执行
2.ScheduledThreadPoolExecutor
- 指定30个线程池,延迟一秒钟后执行
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(30);
executor.schedule(new Runnable() {
@Override
public void run() {
System.out.println("执行了");
}
},1,TimeUnit.SECONDS);
有线程池,可以做延时操作,但是无法实现某个月的某一天执行
二、第三方
1.quartz
功能比较强大,网上的帖子很多,学习成本很低,不多赘述
2.SpringTask
springTask是spring对JDK的任务调度的封装
2.1演示
- 指定两秒钟后执行
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.initialize();
scheduler.setPoolSize(30);
scheduler.schedule(new Runnable() {
@Override
public void run() {
}
},new Date(System.currentTimeMillis()+2000));
- 使用cron表达式指定时间
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.initialize();
scheduler.setPoolSize(30);
scheduler.schedule(new Runnable() {
@Override
public void run() {
System.out.println("执行了");
}
//表示每天中午12点触发
},new CronTrigger("0 0 12 * * ?"));
2.2实际写法
2.2.1注解的方式SpringBoot
- 第一步,添加@EnableScheduling注解开启任务调度
@SpringBootApplication
@EnableTransactionManagement
@MapperScan(basePackages = "com.qy28.sm.mapper")
@EnableScheduling //开启任务调度
public class ProjectApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectApplication.class);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- 在需要开启定时任务的方法上添加@Scheduled注解
// fixedDelay表示定时任务执行时的延时时间,一次任务执行结束到第二次任务开启的时间
// fixedRate表示下次任务执行开始的时间间隔,第一次开始执行的时间,到第二次开始执行时间的间隔
@Scheduled(cron = "0 15 10 ? * *",fixedDelay = 5000,fixedRate = 5000)
public void doSomeThin(){
System.out.println("我要做的事");
}
2.2.2 springTask开启异步任务
springTask是串行操作,默认的任务调度线程池大小只有1,所以我们需要在配置文件中配置调度任务线程池大小
- 第一种方式
spring:
task:
scheduling:
pool:
size: 20 #scheduled调度线程的数量
execution:
pool:
core-size: 20 #异步任务线程池的数量
- 第二种方式
这种方式不需要指定scheduling的poolSize,在调度任务中要执行的操作开启异步任务即可
首先在主配置类上添加@EnableAsync 开启异步任务
@SpringBootApplication
@EnableTransactionManagement
@MapperScan(basePackages = "com.qy28.sm.mapper")
@EnableScheduling //开启任务调度
@EnableAsync //开启异步任务
public class ProjectApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectApplication.class);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
编写调度任务
@Autowired
private UploadUtils uploadUtils;
@Scheduled(cron = "0 15 10 ? * *",fixedDelay = 5000,fixedRate = 5000)
public void doSomeThin(){
String base64 ="xxx";
String ext ="ccc";
uploadUtils.uploadByBase64(base64,ext);
}
在需要调用的方法上添加@Async注解,表示此方法为异步任务
@Async
public String uploadByBase64(String base64,String ext){
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);
String s = base64.split(",")[1];
byte[] bytes = Base64Utils.decodeFromString(s);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
String fileName=System.nanoTime()+ext;
ossClient.putObject(exampleBucket, fileName, inputStream);
// 关闭OSSClient。
ossClient.shutdown();
return "https://afei28.oss-cn-beijing.aliyuncs.com/"+fileName;
}
- 第三方式
手写线程池的方式
第一步:编写一个类获得bean的类
//可以让不在容器中的类获得容器中的类
@Component
public class SpringContainerUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext1) throws BeansException {
applicationContext=applicationContext1;
}
public static <T> T getBean(Class<T> tClass){
return applicationContext.getBean(tClass);
}
}
第二步:编写异步任务管理器
//只需要全局操控一个线程池,所以需要使用单例模式
public class AsyncManager {
private ThreadPoolTaskExecutor poolTaskExecutor;
private static AsyncManager asyncManager;
// 私有化构造方法
private AsyncManager(){
poolTaskExecutor=SpringContainerUtils.getBean(ThreadPoolTaskExecutor.class);
}
//获得实例,如果存在直接返回,不存在就实例化
public static AsyncManager getInstance(){
if (asyncManager==null){
asyncManager=new AsyncManager();
}
return asyncManager;
}
// 调用线程池做异步任务
public void executeByAsync(Runnable runnable){
poolTaskExecutor.execute(runnable);
}
}
第三步:编写Runnable工厂
public class RunnableFactory {
public static Runnable insertBrand(String name){
BrandMapper bean = SpringContainerUtils.getBean(BrandMapper.class);
Brand brand = new Brand();
brand.setBrandName(name);
Runnable runnable = ()->{
bean.insert(brand);
};
return runnable;
}
}
第四步:调用方法开启异步任务
@Scheduled(cron = "0 15 10 ? * *",fixedDelay = 5000,fixedRate = 5000)
public void doSomeThin(){
String name ="aaa";
AsyncManager.getInstance().executeByAsync(RunnableFactory.insertBrand(name));
}