Java教程

定时任务

本文主要是介绍定时任务,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

定时任务的实现

  • timer

  • quartz

  • spring的scheduled

quartz

首先我们来看看quartz的使用。

使用首先要明白quartz的三个核心概念:

  • Job(作业): 表示一个工作,要执行的具体内容。
  • trigger(触发器): 什么时间做
  • scheduler(调度器): 什么时间做什么任务
  • jobDetail: 任务详细描述

基本使用

示例: 每隔5秒中提醒一次该开会了

使用步骤:

  1. 引入依赖
  2. 编写job
  3. 创建jobDetail描述任务,创建触发器,创建调度器,通过调度器调度任务

依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

示例

package demo;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

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

public class RemindJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String remindTime = new SimpleDateFormat("yy-MM-dd HH:mm:ss:SSS").format(new Date());
        System.out.println("提醒时间:" + remindTime + ", 该开会了...");
    }
}

调度器和触发器

package demo;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.concurrent.TimeUnit;

public class SchedulerDemo {

    public static void main(String[] args) throws SchedulerException, InterruptedException {
        // 1、创建调度器Scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        
        // 2、创建 JobDetail 实例,并与 RemindJob 类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(RemindJob.class)
                                        .withIdentity("remindJob", "group1").build();
                                        
        // 3、构建 Trigger 实例,每隔5s执行一次
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("trigger1", "triggerGroup1")
                .startNow()//立即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(5) //每隔5s执行一次
                .repeatForever()) //一直执行
                .build();

        //4、执行
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();

        //睡眠
        TimeUnit.MINUTES.sleep(1);
        scheduler.shutdown();
        System.out.println("--------scheduler shutdown ! ------------");

    }
}

cron触发器

CronTrigger功能非常强大,是基于日历的作业调度,而SimpleTrigger是精准指定间隔,所以相比SimpleTrigger,CroTrigger更加常用。CroTrigger是基于Cron表达式的,先了解下Cron表达式:
由7个子表达式组成字符串的,格式如下:

[秒] [分] [小时] [日] [月] [周] [年]
序号 说明 是否必填 允许填写的值 允许的通配符
1 0-59 , - * /
2 0-59 , - * /
3 0-23 , - * /
4 1-31 , - * ? / L W
5 1-12或JAN-DEC , - * /
6 1-7或SUN-SAT , - * ? / L W
7 empty 或1970-2099 , - * /
通配符表示的意思:
 * 表示每x(秒,分,天,月,日,周几)的意思
 0/5 * * * * ?  :  从0秒开始,每增加5秒执行一次
 0 0/5 * * * ?  :  从0秒开始,每增加5分钟执行一次
 5,8,12 * * * * ?:  ,表示一个列表,表示在每一分钟里面的第5秒,第8秒,第12秒各执行一次
 0 10 8,10,13 * * ?  :  在8点,10点,13点的10分的时候,各执行一次
 0 10 8-12 * * ?:  -表示多少到多少之间,在8点到12的的每小时的第10分钟的时候执行任务
 
 ?:  只能出现在表示日期或值星期几的位置
 W: workday(工作日)
 L: 最后一天,或最后一周的周几
 #: 表示第几周的意思
// 3、构建 Trigger 实例,每隔5s执行一次
Trigger trigger = TriggerBuilder
        .newTrigger()
        .withIdentity("trigger1", "triggerGroup1")
        .startNow()//立即生效
        .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
        .build();

和 spring boot 整合

  1. 引入 spring boot 整合quartz的依赖
  2. 写任务(继承 QuartzJobBean 抽象类)
  3. 配置 jobDetail和trigger对象
  4. 启动springboot项目

任务是继承 QuartzJobBean 抽象类

public class QuartzJob1 extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String remindTime = new SimpleDateFormat("yy-MM-dd HH:mm:ss:SSS").format(new Date());
        System.out.println("提醒时间:" + remindTime + ", 该开会了...");
    }
}

创建配置类

@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail jobDetail1(){
        return JobBuilder.newJob(QuartzJob1.class).storeDurably().build();
    }
     @Bean
    public Trigger trigger1(){
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1) //每一秒执行一次
                .repeatForever(); //永久重复,一直执行下去
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail1())
                .withSchedule(scheduleBuilder)
                .build();
    }
 /*   
         @Bean(name = "jobDetail")
        public MethodInvokingJobDetailFactoryBean detailFactoryBean(TimingTask task) {
            // ScheduleTask为需要执行的任务
            MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
            /*
             *  是否并发执行
             *  例如每3s执行一次任务,但是当前任务还没有执行完,就已经过了3s了.
             *  如果此处为true,则下一个任务会bing执行,如果此处为false,则下一个任务会等待上一个任务执行完后,再开始执行
             */
            jobDetail.setConcurrent(true);
            jobDetail.setName("scheduler");// 设置任务的名字
            jobDetail.setGroup("scheduler_group");// 设置任务的分组,这些属性都可以存储在数据库中,在多任务的时候使用

            /*
             * 这两行代码表示执行task对象中的scheduleTest方法。定时执行的逻辑都在scheduleTest。
             */
            jobDetail.setTargetObject(task);
            jobDetail.setTargetMethod("start");
            return jobDetail;
        }
        
        @Bean
    public JobDetailFactoryBean jobDetail(){
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
        jobDetailFactoryBean.setJobClass(HiJob.class);
        jobDetailFactoryBean.setBeanName("hiJob");
        jobDetailFactoryBean.setGroup("jobGroup");
        jobDetailFactoryBean.setDurability(true);
        return jobDetailFactoryBean;
    }

    @Bean
    public CronTriggerFactoryBean cronTrigger(JobDetailFactoryBean jobDetailFactoryBean){
        CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
        triggerFactoryBean.setCronExpression("0/5 * * * * ?");
        triggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        return triggerFactoryBean;
    }
    */
}

spring的scheduled

在SpringBoot使用Spring Schedule非常简单,因为SpringBoot自身的starter中已经集成了Schedule,而不需要我们做更多的处理。

使用@EnableScheduling注解开启定时功能,该注解可以使用在启动类上,也可以注解于定时任务的类上。然后使用@Scheduled注解配合其参数完成定时任务。

依赖

org.springframework:spring-context 包
  • 在启动类上面使用 @EnableScheduling 开启定时任务
@SpringBootApplication
@EnableScheduling
public class SpringBootQuartzDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootQuartzDemoApplication.class, args);
    }
}

固定延时任务频率任务

  • 在要定时运行的方法上面加注解 @Scheduled
@Component
public class ScheduledComponet {
    private static Logger LOGGER = LoggerFactory.getLogger(ScheduledComponet.class) ;

    @Scheduled(fixedDelay = 5000)
    public void testSheduled() throws InterruptedException {
        TimeUnit.SECONDS.sleep(6);
        LOGGER.info("定时任务1: 线程: [ {} ],[ {} ]",Thread.currentThread().getName(),new Date());
    }

    @Scheduled(fixedRate= 3000)
    public void testSheduled2() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        LOGGER.info("定时任务2: 线程: [ {} ],[ {} ]",Thread.currentThread().getName(),new Date());
    }

    @Scheduled(cron = "0/5 * * ? * *")
    public void testSheduled3() throws InterruptedException {
        TimeUnit.SECONDS.sleep(8);
        LOGGER.info("定时任务3: 线程: [ {} ],[ {} ]",Thread.currentThread().getName(),new Date());
    }

}

注意
多个 @Scheduled 注解的方法是在一个线程中执行的,如果运行比较耗时,会阻塞其他任务的执行,使用 @Async 和 @EnableAsync 开启异步任务,可以解决,会使用异步任务线程池来运行. spring 的 cron 表达式中不允许出现字母.

@SpringBootApplication
@EnableScheduling
@EnableAsync // 开启异步
public class SpringBootQuartzDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootQuartzDemoApplication.class, args);
    }
}
    @Scheduled(fixedDelay = 5000)
    @Async // 方法异步执行
    public void testSheduled() throws InterruptedException {
        TimeUnit.SECONDS.sleep(6);
        LOGGER.info("定时任务1: 线程: [ {} ],[ {} ]",Thread.currentThread().getName(),new Date());
    }
这篇关于定时任务的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!