定时任务简单讲解以及使用

文章目录

  • 定时任务简单讲解以及使用
  • 一、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));
    }