这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
时间轮介绍
从具体实现来看,时间轮 是一个基于 「数组」 实现的 「循环队列」 ,数组的每个元素被称为 「槽(slot)」 ,每个槽中存储着一个 「任务列表」 ,这个任务列表的实现较为多样,可以是 「由双向链表实现」 ,也可以是 「由数组实现」。除了基本的存储结构,时间轮还有一根用于指示当前时间的指针,这根指针同时也用于触发所指向的时间槽内任务。该指针以恒定的速度旋转,每经过一个槽即走过一个单位时间*(所以也可以将槽称为时间槽,因为它即表示时间刻度,也表示存储空间)*,旋转一圈则走过时间轮的一个生命周期。
而上图采用的是多层级时间轮 多层级时间轮从逻辑上和我们日常使用的时钟颇为相似,上一层级的时间轮中的一个时间槽(单位时间)等于下一层级的时间轮的一个时间周期。
Quartz核心概念
-
Scheduler为调度器负责整个定时系统的调度,内部通过线程池进行调度,下文阐述。
-
Trigger为触发器记录着调度任务的时间规则,主要有四种类型:SimpleTrigger、CronTrigger、DataIntervalTrigger、NthIncludedTrigger,在项目中常用的为:SimpleTrigger和CronTrigger。
-
JobDetail为定时任务的信息载体,可以记录Job的名字、组及任务执行的具体类和任务执行所需要的参数
-
Job为任务的真正执行体,承载着具体的业务逻辑。
先由SchedulerFactory创建Scheduler调度器后,由调度器去调取即将执行的Trigger,执行时获取到对于的JobDetail信息,找到对应的Job类执行业务逻辑。
Spring Boot 实现
下面实现的是一个使用Quartz定时将Redis的数据传到mysql中同步。
1. 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2. 配置Quartz
@Configuration
public class QuartzConfig {
private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";
@Bean
public JobDetail quartzDetail(){
return JobBuilder.newJob(FavoriteTask.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();
}
@Bean
public Trigger quartzTrigger(){
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(15)
.repeatForever();
return TriggerBuilder.newTrigger().forJob(quartzDetail())
.withIdentity(LIKE_TASK_IDENTITY)
.withSchedule(scheduleBuilder)
.build();
}
}
3. Job类实现
@Component
public class FavoriteTask extends QuartzJobBean {
@Autowired
FavoriteService favoriteService;
@Autowired
CommentService commentService;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) {
log.info("LikeTask-------- {}", sdf.format(new Date()));
//将 Redis 里的点赞信息同步到数据库里
favoriteService.transFavoriteFromRedis2DB();
favoriteService.transFavoriteCountFromRedis2DB();
commentService.transCommentCountFromRedis2DB();
}
}