定时任务

Posted 517cn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了定时任务相关的知识,希望对你有一定的参考价值。

 

开启定时任务功能

package com.huang.pims;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@ComponentScan(basePackages = {"com.huang.pims.*"})
@EnableCaching
// 开启定时任务功能 @EnableScheduling
public class PimsApplication { public static void main(String[] args) { SpringApplication.run(PimsApplication.class, args); } }

 

创建定时任务的示例

package com.huang.pims.schedule.tasks;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class ScheduledTaskDemo01 {

    /**
     * 每分钟内秒数为3的倍数的时间点皆可以执行任务
     * 如果因执行上一个任务,而错过了一个多个时间点,则需等待至最近的一个时间点方可以继续执行
     * 例如,3,6,9,12,15,18,21等等,这些都是可以执行任务的时间点
     * 如果在时间点6执行了一个耗时7s的任务,那么时间点9和时间点12就无法执行任务,必须等到时间点15,才可以执行下次任务
     *
     * 假设:
     *      执行一次任务需要消耗的时间为 exeTime
     *      执行此次任务的开始时间是 nowTime
     *      执行下一次任务的实际时间是 actuallyTime
     * 那么,
     * while(actuallyTime % 3 == 0 && actuallyTime <= nowTime + exeTime) {
     *      actuallyTime += 3;
     * }
     *
     */
    @Scheduled(cron = "0/3 * * * * *")
    public void cronTask() {
        System.out.println("定时任务:每过3s执行一次任务");
        System.out.println("当前线程:"+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("【定时任务】ScheduledTaskDemo01.cronTask() 开始时间:" + sdf.format(new Date()));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {}
        System.out.println("【定时任务】ScheduledTaskDemo01.delayTask() 结束时间:" + sdf.format(new Date()));
    }


    /**
     * 周期性延迟执行任务
     *
     * 假设:
     *      执行一次任务需要消耗的时间为 exeTime
     *      执行此次任务的开始时间是 nowTime
     *      执行下一次任务的实际时间是 actuallyTime
     * 那么,actuallyTime >= nowTime + exeTime + fixedDelay;
     */
    @Scheduled(fixedDelay = 2000)
    public void delayTask() {
        System.out.println("定时任务:执行完一次任务后,先延迟2秒再执行下一次任务");
        System.out.println("当前线程:"+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("【定时任务】ScheduledTaskDemo01.delayTask() 开始时间:" + sdf.format(new Date()));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        System.out.println("【定时任务】ScheduledTaskDemo01.delayTask() 结束时间:" + sdf.format(new Date()));
    }

    /**
     * 周期性执行任务
     *
     * 假设:
     *      执行一次任务需要消耗的时间为 exeTime
     *      执行此次任务的开始时间是 nowTime
     *      执行下一次任务的实际时间是 actuallyTime
     * 如果 exeTime >= fixedRate ,那么,actuallyTime >= nowTime + exeTime;
     * 如果 exeTime < fixedRate , 那么,actuallyTime >= nowTime + fixedRate;
     */
    @Scheduled(fixedRate = 2000)
    public void periodTask() {
        System.out.println("定时任务:每2秒执行一次");
        System.out.println("当前线程:"+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("【定时任务】ScheduledTaskDemo01.periodTask() 开始时间:" + sdf.format(new Date()));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {}
        System.out.println("【定时任务】ScheduledTaskDemo01.periodTask() 结束时间:" + sdf.format(new Date()));
    }

}

  如果想看到效果,直接启动项目即可。从结果可以看出,这些任务都是由同一条线程串行调度的。如果任务较少,还可以接受,但是如果任务很多,任务也很耗时,那就不适合了。这时可以使用@EnableAsync注解来开启对异步事件的支持,@Async来注解定时任务类或方法。这样可以使得,每次执行的任务都将由一条新的线程来执行。如此,可以使用线程池的技术来进一步优化,毕竟无限的创建、销毁线程很消耗性能。

 

定时任务优化

配置定时任务的线程池

package com.huang.pims;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@SpringBootApplication
@ComponentScan(basePackages = {"com.huang.pims.*"})
@EnableCaching
@EnableScheduling // 开启定时任务
@EnableAsync // 开启异步支持
public class PimsApplication {

    public static void main(String[] args) {
        SpringApplication.run(PimsApplication.class, args);
    }

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(10);// 核心线程数
        taskExecutor.setMaxPoolSize(15);// 最大线程数
        taskExecutor.initialize();
        return taskExecutor;
    }

}

使用了@Async来注解定时任务类

package com.huang.pims.schedule.tasks;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
@Async
public class ScheduledTaskDemo01 {

    /**
     * 每分钟内秒数为3的倍数的时间点皆可以执行任务
     * 如果因执行上一个任务,而错过了一个多个时间点,则需等待至最近的一个时间点方可以继续执行
     * 例如,3,6,9,12,15,18,21等等,这些都是可以执行任务的时间点
     * 如果在时间点6执行了一个耗时7s的任务,那么时间点9和时间点12就无法执行任务,必须等到时间点15,才可以执行下次任务
     *
     * 假设:
     *      执行一次任务需要消耗的时间为 exeTime
     *      执行此次任务的开始时间是 nowTime
     *      执行下一次任务的实际时间是 actuallyTime
     * 那么,
     * while(actuallyTime % 3 == 0 && actuallyTime <= nowTime + exeTime) {
     *      actuallyTime += 3;
     * }
     *
     */
    @Scheduled(cron = "0/3 * * * * *")
    public void cronTask() {
        System.out.println("定时任务:每过3s执行一次任务");
        System.out.println("当前线程:"+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("【定时任务】ScheduledTaskDemo01.cronTask() 开始时间:" + sdf.format(new Date()));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {}
        System.out.println("【定时任务】ScheduledTaskDemo01.delayTask() 结束时间:" + sdf.format(new Date()));
    }


    /**
     * 周期性延迟执行任务
     *
     * 假设:
     *      执行一次任务需要消耗的时间为 exeTime
     *      执行此次任务的开始时间是 nowTime
     *      执行下一次任务的实际时间是 actuallyTime
     * 那么,actuallyTime >= nowTime + exeTime + fixedDelay;
     */
    @Scheduled(fixedDelay = 2000)
    public void delayTask() {
        System.out.println("定时任务:执行完一次任务后,先延迟2秒再执行下一次任务");
        System.out.println("当前线程:"+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("【定时任务】ScheduledTaskDemo01.delayTask() 开始时间:" + sdf.format(new Date()));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        System.out.println("【定时任务】ScheduledTaskDemo01.delayTask() 结束时间:" + sdf.format(new Date()));
    }

    /**
     * 周期性执行任务
     *
     * 假设:
     *      执行一次任务需要消耗的时间为 exeTime
     *      执行此次任务的开始时间是 nowTime
     *      执行下一次任务的实际时间是 actuallyTime
     * 如果 exeTime >= fixedRate ,那么,actuallyTime >= nowTime + exeTime;
     * 如果 exeTime < fixedRate , 那么,actuallyTime >= nowTime + fixedRate;
     */
    @Scheduled(fixedRate = 2000)
    public void periodTask() {
        System.out.println("定时任务:每2秒执行一次");
        System.out.println("当前线程:"+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("【定时任务】ScheduledTaskDemo01.periodTask() 开始时间:" + sdf.format(new Date()));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {}
        System.out.println("【定时任务】ScheduledTaskDemo01.periodTask() 结束时间:" + sdf.format(new Date()));
    }

}

  开启项目,即可看到定时任务的效果。

 

 

  

 

以上是关于定时任务的主要内容,如果未能解决你的问题,请参考以下文章

Celery实现定时任务crontab

以代码的方式管理quartz定时任务的暂停重启删除添加等

Laravel实现定时任务的示例代码

asp.net 定时器 定时执行任务

MySQL定时执行脚本(计划任务)实例

动态创建管理定时任务-已完成