对于服务端的多线程定时任务,需要怎么使用呢,其实很简单,仅需两步(创建线程池+开启定时任务),快来看看吧
1.首先第一步,创建好定时任务线程池(这里创建了两个,可根据业务需求进行扩展):
package com.digitalgd.goff.service.task;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author yangli
* @ClassName ThreadPoolConfig
* @Description 线程池配置
* @date 2020/7/10 16:13
**/
@EnableAsync
@Configuration
public class TaskPoolConfig {
@Bean("mailNumPoolSingleTaskExecutor")
public Executor mailNumPoolSingleTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置为1,任务顺序执行
executor.setCorePoolSize(1);//核心线程数:线程池创建时候初始化的线程数
executor.setMaxPoolSize(1);//最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setQueueCapacity(20);//缓冲队列200:缓冲执行任务的队列
executor.setKeepAliveSeconds(60);//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setThreadNamePrefix("mailNumPoolSingleTaskExecutor-");//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());// 线程池对拒绝任务的处理策略
return executor;
}
@Bean("otherSingleTaskExecutor")
public Executor otherSingleTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置为1,任务顺序执行
executor.setCorePoolSize(1);//核心线程数:线程池创建时候初始化的线程数
executor.setMaxPoolSize(1);//最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setQueueCapacity(20);//缓冲队列200:缓冲执行任务的队列
executor.setKeepAliveSeconds(60);//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setThreadNamePrefix("otherSingleTaskExecutor-");//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());// 线程池对拒绝任务的处理策略
return executor;
}
}
2.创建好线程池后,就可以正式开始定时任务使用了:
package com.digitalgd.goff.service.task;
import com.digitalgd.goff.service.ServiceMonitoringService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
/**
* @author yangli
* @ClassName ServiceMonitorTask
* @Description 定时任务
* @date 2020/7/10 16:13
**/
@Component
@Slf4j
@EnableScheduling
@EnableAsync
public class ServiceMonitorTask {
@Scheduled(cron = "0 0 8,16 * * ?") // 标明此方法为定时任务
@Async("otherSingleTaskExecutor") // 通过注解指定使用的线程池
public void serviceUseCountTask(){
log.info("服务被调用情况start");
try {
log.info("服务被调用情况end");
} catch (Exception e) {
log.info("服务调用error");
}
}
@Scheduled(cron = "0 30 8,16 * * ?")
@Async("otherSingleTaskExecutor")
public void healthStatusTask(){
log.info("服务统计start");
try {
log.info("服务统计end");
} catch (Exception e) {
log.info("服务统计error");
}
}
@Scheduled(cron = "0 0 0,12 * * ?")
@Async("otherSingleTaskExecutor")
public void requestCountTask(){
log.info("服务请求数---------");
}
}
关于注解:
@Async是spring为了方便开发人员进行异步调用的出现的,在方法上加入这个注解,spring会从线程池中获取一个新的线程来执行方法,实现异步调用
@EnableAsync表示开启对异步任务的支持,可以放在springboot的启动类上,也可以放在自定义线程池的配置类上
@EnableScheduling:开启对定时任务的支持,在相应的方法上添加@Scheduled声明需要执行的定时任务。
@Scheduled(cron = “0 0 8,16 * * ?”) , 标明此方法为需要执行的定时任务,cron表达式由6到7个时间元素组成,每个字符表示一个时间含义,从左到右(用空格隔开),依次表示为:
秒 分 小时 月份中的日期 月份 星期 年份
四.注解没生效的原因
1.异步方法使用static修饰
2.异步方法类没有使用@Service注解(或其他注解)导致spring无法扫描到异步类
3.controller中需要使用@Autowired或@Resource等注解自动注入service类,不能自己手动new对象
到此为止定时任务的配置就已经全部结束,快来愉快的使用吧!