任务调度框架Quartz快速入门

超重要API

==========

  • Scheduler 和调度程序交互的主要API生命周期从SchedulerFactoru创建它开始,到调用shutdown方法结束。一旦Scheduler创建,任何关于scheduling相关的事,他都为所欲为:添加、删除、列出所有的Jobs和triggers、暂停触发器等。在start方法之前,不会做任何事情。

  • Job 你希望被调度器调度的任务组件接口。当Job的触发器触发时,调度程序的工作线程将调用execute方法。该方法接收一个JobExecutionContext对象,为Job实例提供了丰富的运行时环境信息,比如:scheduler、trigger、jobDataMap、job、calendar、各种time等。

  • JobDetail 用于定义任务。JobDetail对象由Quartz客户端在将job加入Scheduler提供,也就是你的程序。它包含了不同为job设置的属性,还有可以用来为job储存状态信息的JobDataMap。注意它和Job的区别,它实际上是Job实例的属性。【Job定义如何执行,JobDetail定义有何属性】

  • Trigger 触发任务执行。触发器可能具有与之关联的JobDataMap,以便于将特定于触发器触发的参数传递给Job。Quartz提供了几种不同的触发器,SimpleTrigger和CronTrigger比较常用。如果你需要一次性执行作业或需要在给定的时间触发一个作业并重复执行N次且有两次执行间有延时delay,SimpleTrigger较为方便。如果你希望基于类似日期表触发执行任务,CronTrgger推荐使用。

  • JobBuilder 用于构建JobDetail的。

  • TriggerBuilder 用于构建Trigger的。

Quartz提供了各种各样的Builder类,定义了Domain Specific Language,且都提供了静态的创建方法,我们可以使用import static简化书写。

重要概念

========

  • Identity当作业和触发器在Quartz调度程序中注册时,会获得标识键。JobKey和TriggerKey允许被置入group中,易于组织管理。唯一的,是name和group的组合标识。

  • JobDataMap是Map的实现,具有key-value相关操作,存储可序列化数据对象,供Job实例在执行时使用。可以使用usingJobData(key,value)在构建Jobdetail的时候传入数据,使用jobDetail.getJobDataMap()获取map。

Quartz设计理念:为什么设计Job和Trigger?

================================

While developing Quartz, we decided that it made sense to create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits. For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job. Another benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired, so that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define its associated job.

隔离schedule和schedule上执行的Job,优点是可见的:

可以独立于触发器创建作业并将其存储在作业调度程序中,并且许多触发器可以与同一作业相关联。这样的松耦合好处是什么?

  • 如果触发器过期,作业还可以保留在程序中,以便重新调度,而不必重新定义。

  • 如果你希望修改替换某个触发器,你不必重新定义其关联的作业。

最简单的Quartz使用案例

==================

导入依赖

org.quartz-scheduler

quartz

2.3.2

简单案例如下

public class QuartzTest {

// 你需要在start和shutdown之间执行你的任务。

public static void main(String[] args) {

try {

// 从工厂中获取Scheduler示例

Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

// 开始

scheduler.start();

// 定义Job,并将其绑定到HelloJob类中

JobDetail job = JobBuilder.newJob(HelloJob.class)

.withIdentity(“job1”, “group1”) // name 和 group

.usingJobData(“username”, “天乔巴夏”) // 置入JobDataMap

.usingJobData(“age”, “20”)

.withDescription(“desc-demo”)

.build();

// 触发Job执行,每40s执行一次

Trigger trigger = TriggerBuilder.newTrigger()

.withIdentity(“trigger1”, “group1”)

.startNow() // 立即开始

.withSchedule(SimpleScheduleBuilder.simpleSchedule()

.withIntervalInSeconds(40)

.repeatForever())

.build();

// 告诉 quartz 使用trigger来调度job

scheduler.scheduleJob(job, trigger);

// 关闭,线程终止

scheduler.shutdown();

} catch (SchedulerException se) {

se.printStackTrace();

}

}

}

@Slf4j

@NoArgsConstructor

public class HelloJob implements Job {

@Override

public void execute(JobExecutionContext context) throws JobExecutionException {

// 从context中获取属性

JobDetail jobDetail = context.getJobDetail();

JobDataMap jobDataMap = jobDetail.getJobDataMap();

JobKey key = jobDetail.getKey();

Class<? extends Job> jobClass = jobDetail.getJobClass();

String description = jobDetail.getDescription();

String username = jobDataMap.getString(“username”);

int age = jobDataMap.getIntValue(“age”);

log.info(“\nJobKey : {},\n JobClass : {},\n JobDesc : {},\n username : {},\n age : {}”,

key, jobClass.getName(), description, username, age);

}

}

启动测试,打印日志如下:

01:23:12.406 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor

01:23:12.414 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main

01:23:12.430 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl

01:23:12.430 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.

01:23:12.432 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.

01:23:12.433 [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.

01:23:12.433 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler ‘DefaultQuartzScheduler’ initialized from default resource file in Quartz package: ‘quartz.properties’

01:23:12.433 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2

01:23:12.434 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.

01:23:12.434 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers

01:23:12.443 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers

01:23:12.445 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job ‘group1.job1’, class=com.hyhwky.HelloJob

01:23:12.451 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers

01:23:12.452 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1

01:23:12.452 [DefaultQuartzScheduler_Worker-1] INFO com.hyhwky.HelloJob -

JobKey : group1.job1,

JobClass : com.hyhwky.HelloJob,

JobDesc : desc-demo,

username : 天乔巴夏,

age : 20

我们可以看到quartz已经被初始化了,初始化配置如下,在org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\quartz.properties

调度器配置

org.quartz.scheduler.instanceName: DefaultQuartzScheduler

org.quartz.scheduler.rmi.export: false

org.quartz.scheduler.rmi.proxy: false

org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

线程池配置

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount: 10

org.quartz.threadPool.threadPriority: 5

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总目录展示

该笔记共八个节点(由浅入深),分为三大模块。

高性能。 秒杀涉及大量的并发读和并发写,因此支持高并发访问这点非常关键。该笔记将从设计数据的动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化这4个方面重点介绍。

一致性。 秒杀中商品减库存的实现方式同样关键。可想而知,有限数量的商品在同一时刻被很多倍的请求同时来减库存,减库存又分为“拍下减库存”“付款减库存”以及预扣等几种,在大并发更新的过程中都要保证数据的准确性,其难度可想而知。因此,将用一个节点来专门讲解如何设计秒杀减库存方案。

高可用。 虽然介绍了很多极致的优化思路,但现实中总难免出现一些我们考虑不到的情况,所以要保证系统的高可用和正确性,还要设计一个PlanB来兜底,以便在最坏情况发生时仍然能够从容应对。笔记的最后,将带你思考可以从哪些环节来设计兜底方案。


篇幅有限,无法一个模块一个模块详细的展示(这些要点都收集在了这份《高并发秒杀顶级教程》里),麻烦各位转发一下(可以帮助更多的人看到哟!)

由于内容太多,这里只截取部分的内容。
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
一个PlanB来兜底,以便在最坏情况发生时仍然能够从容应对。笔记的最后,将带你思考可以从哪些环节来设计兜底方案。


篇幅有限,无法一个模块一个模块详细的展示(这些要点都收集在了这份《高并发秒杀顶级教程》里),麻烦各位转发一下(可以帮助更多的人看到哟!)

[外链图片转存中…(img-Qmf1iOWP-1711883503650)]

[外链图片转存中…(img-GP9wEHv4-1711883503650)]

由于内容太多,这里只截取部分的内容。
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值