接手公司的代码在使用 quartz 中使用了,最近在开发新功能,突然任务都阻塞的,后面发现是是因为改动了一部分代码导致执行了这部分代码
1 | trigger = TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME).startAt(startTime).endAt(endTime).build(); |
远程访问线程后显示我没有设置withSchedule 导致一直访问
SELECT * FROM T_QRTZ_LOCKS WHERE SCHED_NAME = ‘quartzScheduler_dq’ AND LOCK_NAME = ‘TRIGGER_ACCESS’ FOR UPDATE
研究了一下在 Quartz 调度框架中,触发器(Trigger)是用于定义任务的启动、结束时间、重复执行间隔等细节的。当没有设置 withSchedule
时,Quartz 默认的行为是认为这个触发器是一个“一次性”触发器,即在 startAt
指定的时间启动,并且不会重复执行。
然而,T_QRTZ_LOCKS
表格是 Quartz 用来管理锁和调度状态的数据库表,LOCK_NAME = 'TRIGGER_ACCESS'
说明当前 Quartz 调度器正在尝试获取对某个资源的锁,可能是在创建或执行触发器时遇到了并发问题。具体来说,这种情况可能是由于以下原因导致的:
- 锁的竞争:创建的触发器没有明确的调度计划(例如,没有设置
withSchedule
),可能导致 Quartz 试图获取资源的锁,而该锁在其他地方已经被占用。Quartz 会用数据库表T_QRTZ_LOCKS
来保证分布式环境中不同调度器的协调,防止重复执行。正在尝试访问的锁是TRIGGER_ACCESS
,Quartz 在执行时检查并锁定资源,以防止多个实例同时执行同一个任务。 - 没有指定调度计划(Schedule):如果没有设置
withSchedule
,Quartz 会认为这个任务没有重复执行的计划,这意味着每次启动时,Quartz 可能会频繁地访问锁,造成资源竞争。
目前解决方案:
设置触发器的调度计划:可以使用
withSchedule
来设置触发器的调度计划1
trigger = TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME).startAt(startTime).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(60) // 每60秒执行一次.repeatForever()) // 重复执行.build();`
- 检查并发执行:如果系统是分布式的,确保 Quartz 实例之间的锁定机制正常工作。Quartz 通过数据库锁来防止多个调度器同时处理同一个任务,确保任务的唯一执行。