Java定时任务调度(2)Quart框架的简单介绍

421 阅读5分钟

这是我参与新手入门的第2篇文章。

一、前言

在之前的文章《Java定时任务调度(1)TimerTask原理与实战》中已经介绍了一种实现定时任务调度的方法——Java原生提供的 TimerTask,这个工具适用于一些简单的业务需求。

回顾一下,TimerTask的原理总结起来就是下面这个图:

image.png

其实仔细想想,是不是可以抽象出来几个部分?

任务调度,首先要有任务,TimerTask就是 具体任务。有了任务之后是不是要给这个任务设置一下啥时候调,多久调一次,啥时候终止啊?这一步可以叫做 条件设置。那么剩下的就是具体执行,可以叫做 执行器

image.png

其实就具体代码上来说,后两个都是调Timer的方法

    Timer timer = new Timer();
    long delay = 0;
    long period = 1000;
    timer.schedule(timerTask, delay, period);

但是,Timer存在一个严重的问题,它是 单线程 的。

如果你有多个任务,且第一个任务执行时间超过了两个任务的间隔时间,那么第二个任务就不能按时执行,此时可以选择使用ScheduledExecutorService来解决,它的内部是个线程池,此外它也能解决上篇文章中提到的Timer异常退出问题。

二、Quartz的简单介绍

那么接下来,就按照这个思路来介绍一个更强大的Java任务调度框架——Quartz

Quartz有一个官方版的简单介绍:

Quartz 允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz 的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。

 如果从来没有接触过任务调度的东西,光看这肯定也懵,不过相信你看完全篇再回过头来,就明白了。

说来也巧,Quartz的设计思路就是上面总结的三部分,只不过名字不同。

  • Job:具体要执行的任务逻辑

  • Trigger:触发器,设置Job的触发条件、间隔,终止时间

  • Scheduler:调度器,启动Trigger执行Job

这么看是不是和前言中对TimerTask的总结一致了?

Quartz Demo的创建

如果使用传统方式,就是去官方下载一个jar包,新建一个Java project,导包就可以了。 现在一般都是使用自动化构建工具了。

打开start.spring.io/ 填写相关配置,这里我使用Maven

image.png

当然此处也可以选择右侧的add dependencies,那我一般都是自己在pom文件中添加依赖。

导入依赖

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

写Demo

	public static void main(String[] args) {
		 try {
             // 工厂方法获取默认的调度器
             Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

             // 启动
             scheduler.start();
             //关闭
             scheduler.shutdown();

         } catch (SchedulerException se) {
             se.printStackTrace();
         }
	}

其实这个例子是官网提供的【www.quartz-scheduler.org/documentati… 很简单,一共就三行代码。

执行结果是什么那?

22:47:27.348 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
22:47:27.355 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
22:47:27.370 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
22:47:27.370 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
22:47:27.371 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
22:47:27.372 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

22:47:27.372 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
22:47:27.372 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
22:47:27.372 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
22:47:27.372 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
22:47:27.372 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
22:47:27.372 [main] DEBUG org.quartz.simpl.SimpleThreadPool - Shutting down threadpool...
22:47:27.372 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
22:47:27.372 [main] DEBUG org.quartz.simpl.SimpleThreadPool - Shutdown of threadpool complete.
22:47:27.372 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
22:47:27.868 [DefaultQuartzScheduler_Worker-6] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-10] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-5] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-4] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-3] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.869 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.869 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-7] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-8] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
22:47:27.868 [DefaultQuartzScheduler_Worker-9] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

输出的结果还是有很多看头的

Quartz Scheduler v.2.3.2 created  可以看到使用版本
RAMJobStore initialized  可以看到存储方式是RAMJobStore
最后面的SimpleThreadPool 就是线程池,一共有1-10   10个线程

看到线程池,你会想到什么?

可以参考我的上篇文章:《Java定时任务调度(1)TimerTask原理与实战》

假如我把第三行代码注释掉,会发生什么? 注意箭头的位置,这个程序并没有停止。

image.png 这里官网也有解释:

Once you obtain a scheduler using StdSchedulerFactory.getDefaultScheduler(), your application will not terminate until you call scheduler.shutdown(), because there will be active threads.

一旦使用StdSchedulerFactory.getDefaultScheduler()获得调度程序,在调用scheduler.shutdown()之前,应用程序不会终止,因为会有活动线程。

有了启动和停止,任务的具体执行自然就在这中间来完成。

image.png

把官网的例子复制过来,很明显,出现了错误。 具体原因就是一个是没有HelloJob这个类,另一个静态导入要补上

public class HelloJob implements Job{

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		// TODO Auto-generated method stub
		
		SimpleDateFormat  simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		System.out.println("你好!当前时间是:"+simpleDateFormat.format(new Date()));
	}
	
}


//注意,静态导入不在这个HelloJob类中

import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;

当然在执行之前,一定要在停止的前面加上Thread.sleep(),要不然,直接就关闭了。

为了尽快的看到效果,我把间隔时间设置为5秒

效果:

image.png

好了,简单的Demo就写好了。

更详细深入的内容在后续文章中~