Timer

只使用一个参数,会在指定的时间后运行,单位毫秒,但是只会执行一次

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        System.out.println("一秒后执行一次");
    }
}, 1000);

使用一个参数,单位Date对象,会在指定的日期运行一次

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2022); // 控制年
calendar.set(Calendar.MONTH, 8); // 控制月 这里注意,月份是按国外的月份,8就是9月
calendar.set(Calendar.DAY_OF_MONTH, 4); // 控制日
calendar.set(Calendar.HOUR, 12); // 控制时
calendar.set(Calendar.MINUTE, 0);       // 控制分
calendar.set(Calendar.SECOND, 0);       // 控制秒

Date time = calendar.getTime();         // 得出执行任务的时间,此处为Thu Sep 05 00:00:00 CST 2022

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        System.out.println("固定年月日执行一次");
    }
}, time);

上面使用一个参数只会运行一次程序,我们多数情况下肯定是在每过一定的时间执行一次,比如每过一秒执行一次

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        System.out.println("0毫秒后每过一秒执行一次");
    }
}, 0,1000);

也可以使用指定的日期然后每过一秒执行一次

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2022); // 控制年
calendar.set(Calendar.MONTH, 8); // 控制月 这里注意,月份是按国外的月份,8就是9月
calendar.set(Calendar.DAY_OF_MONTH, 4); // 控制日
calendar.set(Calendar.HOUR, 12); // 控制时
calendar.set(Calendar.MINUTE, 0);       // 控制分
calendar.set(Calendar.SECOND, 0);       // 控制秒

Date time = calendar.getTime();         // 得出执行任务的时间,此处为Thu Sep 05 00:00:00 CST 2022

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        System.out.println("2022年9月4号中午十二点开始执行,每秒执行一次");
    }
}, time,1000);

ScheduledExecutorService

使用Timer是单线程的形式,而ScheduledExecutorService是线程池的方式,,这是最理想的定时任务方式

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("使用线程的方式执行,第一个参数是线程,第二个参数是什么时候执行");
    }
}, 1, TimeUnit.SECONDS);

当然我们也可以每过指定时间执行一次,比如一秒执行一次

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("使用线程的方式执行,第一个参数是线程,第二个参数是什么时候执行,第三个参数过多久再次执行");
    }
}, 0,1,TimeUnit.SECONDS);

Quartz

首先使用quartz不是java自带的包所以需要导入jar包,这里我们使用maven

进行导入

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

然后我们创建一个类实现Job类,在里面写上我们需要执行的定时任务,这里我们编写一个新的类

public class QuertzJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("任务被执行了");
    }
}

然后我们在创建一个测试类

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

        //4、执行
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();
//        当任务执行一分钟后就停止任务
        Thread.sleep(1000*60);
        scheduler.shutdown();
    }
}

cron表达式

public class Quartzmain {
    public static void main(String[] args) throws Exception {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // 2、创建JobDetail实例,并与自己写的Job类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(QuertzJob.class)
                .withIdentity("job1", "group1").build();
                
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1","triggerGroup1")
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("5/6 * * * * ? "))//程序开始五秒后执行一次然后每六秒执行一次
                .build();

        //4、执行
        scheduler.scheduleJob(jobDetail, cronTrigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();
//        当任务执行一分钟后就停止任务
        Thread.sleep(1000*60);
        scheduler.shutdown();
    }
}

Spring整合Quartz

首先我们创建一个简单的定时任务,测试成功后再尝试使用cron表达式的定时任务

简单的定时任务

第一步导入spring依赖,这里注意,导入的是spring-context-support这个依赖,不要导入成了spring-context

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

然后还要导入tx

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

再导入quart的依赖

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

依赖导入好了就可以开始编写需要执行的定时的任务代码

public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("执行任务");
    }
}

然后在spring上下文配置定时器的JobDetail和simpleTrigger触发器,最后再绑定即可,这里和没有整合spring是一样的,只不过整合之后是将bean的创建交给spring

<bean id="job" class="spring.MyJob"></bean>
<!-- 2.任务触发器详细信息bean -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

    <property name="jobClass" value="spring.MyJob"></property>
</bean>

<!--第二步:2. 定义触发器,并且将jobDetail注入 -->
<bean id="simpleTrigger"
      class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail" />
    <!-- 调度工厂实例化后,经过3秒开始执行调度 -->
    <property name="startDelay" value="3000" />
    <!-- 每隔2秒执行一次 -->
    <property name="repeatInterval" value="2000" />
</bean>

<!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
<!-- 第三步:配置调度工厂  -->
<bean id="startQuertz" lazy-init="false" autowire="no"
      class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <!-- 管理trigger -->
    <property name="triggers">
        <list>
            <ref bean="simpleTrigger" />
        </list>
    </property>
</bean>

最后直接创建一个测试类启动即可

public class test {

    public static void main(String[] args) {
        ApplicationContext ApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}

这里因为不是springboot的项目就只能这样启动,获取上下文配置然后启动

cron表达式的定时任务

首先我们还是依赖都不变,只需要更改xml的配置

<bean id="job" class="spring.MyJob"></bean>


<!-- 2.任务触发器详细信息bean -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

    <property name="jobClass" value="spring.MyJob"></property>
</bean>

<!-- 第二种 CronTriggerBean,支持到指定时间运行一次,如每天12:00运行一次等。配置方式如下: -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="cronExpression" value="0 4 22 * * ?" />
</bean>


<!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
<!-- 第三步:配置调度工厂  -->
<bean id="startQuertz" lazy-init="false" autowire="no"
      class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <!-- 管理trigger -->
    <property name="triggers">
        <list>
            <ref bean="cronTrigger" />
        </list>
    </property>
</bean>

可以看到我们只是将简单的触发器更改成了cron表达式触发器,其他的配置都没有动

spring整合quartz实现方式

这里在第一次创建简单的定时任务时使用的是实现Job接口

public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("执行任务");
    }
}

当然我们也可以使用继承QuartzJobBean的方式

public class MyJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("任务执行了");
    }
}