quartz定时任务原理-石英定时器工作原理
嘿,聊聊 Quartz 定时任务,这事儿别整那些虚头巴脑的术语堆砌。咱就把它想象成家里的闹钟,但不是那种秒针飞快的机械表,它是那种笨重的、能按指令慢慢走一的机械表。 Quartz 就是那个被锁在抽屉里、平时没人摸、一到工夫自己咔哒一声响的零件。 大量人一见面就跳出来讲“定时器(Timer)”和“调度器(Schedulable)”,听着挺高大上,实际上有点乱。 Quartz 是个通用框架,它是个中军,统筹全局。它负责把任务从你的代码里“抓”出来,然后扔进一个队列里排队等着。
这队列不是好办的 FIFO(先进先出),它是准时的 FIFO,你得记住这个。 最早的时候,Quartz 是纯 Java 写的,后来为了好运维,包装进了 Quartz 2.6,再后来更香了。2.6 之前,你得自己写 Java API 调底层,写起来那是真比写 PPT 还累,并且时常出于并发难题菜鸡都要挂。Quartz 2.6 之后,引入了 JobContext,这个玩意儿简直是 Quartz 的“核心芯片”。
不管你是直接写 Quartz,还是用 C3 框架,你只要在 JobContext 里定义任务,都算是 Quartz 的。
这就好比你是个程序员,但 Quartz 是那个负责把任务的代码交给工厂、发给仓库的搬运工。 说到“调度器”,千万别把它理解为一般/平平的定时器。
一般/平平的定时器是“看天进食”,等工夫到了才动,但这彻底不够用。咱们老板要的是“看人脸色”,要么更狠点说,是“按件算账”。
比方说,周一上午 9 点,你要发工资;每周五下午 2 点,你要发业绩报告。
这些都不是随机事件,它们有固定的周期,有固定的触发条件。
这时候,调度器的活儿就显眼了。调度器是 Quartz 家族里的“英雄”,它是那个拿着红头文件的人。 在 Quartz 的世界里,工夫不是线性的,它是分层的。有个概念叫“粒度”(Granularity),它拍板了 Quartz 的工夫切分精度。
这个粒度拍板了你能切分多细的工夫段。
比如你想精确到毫秒,就得用 Quartz 3 的“单位”(Unit)粒度。单位是个整数,你能够用 `1000` 代表 1 秒,要么`10` 代表 10 秒。
这玩意儿跟 Java 的 `long` 要么 `Double` 不一样,它不是复用的,是唯一的。 举个例子,这就好比你要派一个送外卖的。
要是你规定每隔 10 分钟发一次,那就是 10 秒一个单位。
这时候,Quartz 会切分出一千个工夫切片,每个切片 10 秒。一分钟内,有 60 个切片在跑。
要是这个单位是 1000(1 秒),那每分钟就有 6000 个切片在跑。
这速度要是按传统代码写,CPU 都得冒烟,任务要跑慢,就连挂掉。Quartz 了得就了得在能利用这些切片来优化调度。 比如你要处理一批订单,需求更新库存。
要是你当作每个订单都要跑一次,那库存可能被打乱。你能够设定:每 10 秒切分一次。
那么,这一分钟内,算出每个订单该在第几秒处理。所有订单的任务,都会被放入同一个“切片队列”里。
只有当某个切片的工夫到了,Quartz 才会把这个切片的所有任务,一个个拿出来,一个一个去执行。
这样,100 个订单只会在 10 秒内搞定 10 次更新,而不是 100 次。
这简直是把 Apache Commons DateUtil 的功劳干了一半,但这归 Quartz 所有。 大量人会问,为啥不用 Java 自带的 Scheduler?Java 1.8 赶明儿,`ScheduledExecutorService` 能跑高并发。但 Quartz 不是那种“跑得快”,它是那种“稳”。Java 的调度器是单线程的,别看快,但一旦任务多了,就得排队轮询。Quartz 是多线程的,它有自己的核心线程池,把任务分发给不同的线程跑,互不干扰。
这就像是瑞士军刀,有的刀挺好,有的刀挺钝,但 Quartz 里的刀,都是亲生的,并且能批量处理,还能并行执行。 还有一个关键点,就是 Quartz 的“持久化”。Java 进程挂了,数据还在吗?Quartz 2.6 之前,任务好办丢失(出于没持久化)。Quartz 3 之后,引入了“持久化存”。当你把任务扔进 Quartz 的存区,它有个专门的存服务,不管你的进程如何跑,只要重启,它记得那 100 个任务在那呢。
这就像你造了一辆公交车,把乘客扔进车里,就算你开车回上海,公交车也会把你从车上接下来。
这在 Java 项目里简直是刚需。 再说说“触发器”和“触发类型”。Quartz 把触发分成了三种:`TIME`、`CLOCK` 和 `RANGE`。`TIME` 是固定的工夫点,比如 9:00。`CLOCK` 是随机的工夫,比如 9:00 ± 2 分钟。`RANGE` 是工夫段,比如 9:00 到 10:00。 举个好办的例子,你要每天早上给员工发报告。环境可能不稳定,人可能迟到。你不能用`TIME`,出于只有 9:00 才给。你也不能用`CLOCK`,出于要是某人早上 9:05 来,你要把报告发给他吗?那得看啥算法。
这时候用`RANGE`最合适。它说:只要 9:00 到 10:00 之间,只要人醒了、能看到显示器,就给我报告。
这比`TIME`强多了,它给了调度器挺大的自由度。 还有一个细节,就是“调度器”和“任务”的关系。你定义一个 Quartz 任务,它有一个状态。
比如刚跑完,状态是`EXPIRING`(即将过期),这说明它的触发工夫到了,预备去执行。
要是状态变成`RUNNING`,那是它正在跑。
要是它跑完了,状态变成`DONE`。
要是它被取消了,状态变成`CANCELLED`。
这个状态流转,是 Quartz 工作流的灵魂。 在代码里如何操作呢?你别想得忒复杂。你自己写 Quartz 2.6 之前,你得写一堆 Java API。目前,你只要写一个类,继承 `JobContext`,实现 `start()`、`stop()`、`execute()` 这些方式,然后注册给 Quartz。Quartz 干了剩下的活:毫秒级的切分,队列的管理,线程的调度。你只管写业务逻辑。 那到底如何调优?千万别盲目调大粒度。
比如你设置了 1 秒一个单位,CPU 可能都要烧焦了。你得根据业务判断,“一天跑多少任务”和“切分多少粒度”的平衡点在哪儿。
一般,任务总量除以切分粒度,等于并发线程数。
这个公式别看好办,但挺管用。 最终总结一下。Quartz 不是那种让你去写底层、然后指望它自动成熟的库。它是个工具,是个框架,是个帮你把业务逻辑剥离出来的钩子。它解决了“定时”这个痛点,但又没解决“复杂”这个难题。复杂的时候,你得配合调度器、持久化存和对的触发器类型,把天捅个窟窿。 别再把它当成一个神坛了。它是个肌肉发达的搬运工,没错,但别指望它能一个人扛下整个工厂的运转。你得给它点水(配置),给它喂点好吃的(调度器),还得让它知道该往哪边跑(触发器)。
这才是征服 Quartz 的真正方式。
声明:演示网站所有内容,若无特殊说明或标注,均来源于网络转载,仅供学习交流使用,禁止商用。若本站侵犯了你的权益,可联系本站删除。
