com.github.zhangxd1989.basetool.cron.Scheduler Maven / Gradle / Ivy
package com.github.zhangxd1989.basetool.cron;
import com.github.zhangxd1989.basetool.collection.CollectionUtil;
import com.github.zhangxd1989.basetool.cron.listener.TaskListener;
import com.github.zhangxd1989.basetool.cron.listener.TaskListenerManager;
import com.github.zhangxd1989.basetool.cron.pattern.CronPattern;
import com.github.zhangxd1989.basetool.cron.task.InvokeTask;
import com.github.zhangxd1989.basetool.cron.task.RunnableTask;
import com.github.zhangxd1989.basetool.cron.task.Task;
import com.github.zhangxd1989.basetool.log.StaticLog;
import com.github.zhangxd1989.basetool.setting.Setting;
import com.github.zhangxd1989.basetool.thread.ExecutorBuilder;
import com.github.zhangxd1989.basetool.thread.ThreadFactoryBuilder;
import com.github.zhangxd1989.basetool.util.CharUtil;
import com.github.zhangxd1989.basetool.util.StrUtil;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
/**
* 任务调度器
*
* 调度器启动流程:
*
* 启动Timer =》 启动TaskLauncher =》 启动TaskExecutor
*
* 调度器关闭流程:
*
* 关闭Timer =》 关闭所有运行中的TaskLauncher =》 关闭所有运行中的TaskExecutor
*
* 其中:
*
* TaskLauncher:定时器每分钟调用一次(如果{@link Scheduler#isMatchSecond()}为true
每秒调用一次),
* 负责检查TaskTable是否有匹配到此时间运行的Task
*
*
* TaskExecutor:TaskLauncher匹配成功后,触发TaskExecutor执行具体的作业,执行完毕销毁
*
*
* @author sheldon
*/
public class Scheduler {
private final Object lock = new Object();
/**
* 时区
*/
private TimeZone timezone;
/**
* 是否已经启动
*/
private boolean started = false;
/**
* 是否支持秒匹配
*/
protected boolean matchSecond = false;
/**
* 是否为守护线程
*/
protected boolean daemon;
/**
* 定时器
*/
private CronTimer timer;
/**
* 定时任务表
*/
protected TaskTable taskTable = new TaskTable(this);
/**
* 启动器管理器
*/
protected TaskLauncherManager taskLauncherManager;
/**
* 执行器管理器
*/
protected TaskExecutorManager taskExecutorManager;
/**
* 监听管理器列表
*/
protected TaskListenerManager listenerManager = new TaskListenerManager();
/**
* 线程池,用于执行TaskLauncher和TaskExecutor
*/
protected ExecutorService threadExecutor;
/**
* 设置时区
*
* @param timezone 时区
* @return this
*/
public Scheduler setTimeZone(TimeZone timezone) {
this.timezone = timezone;
return this;
}
/**
* 获得时区,默认为 {@link TimeZone#getDefault()}
*
* @return 时区
*/
public TimeZone getTimeZone() {
return timezone != null ? timezone : TimeZone.getDefault();
}
/**
* 设置是否为守护线程
* 如果为true,则在调用{@link #stop()}方法后执行的定时任务立即结束,否则等待执行完毕才结束。默认非守护线程
*
* @param on true
为守护线程,否则非守护线程
* @return this
* @throws CronException 定时任务已经启动抛出此异常
*/
public Scheduler setDaemon(boolean on) throws CronException {
synchronized (lock) {
if (started) {
throw new CronException("Scheduler already started!");
}
this.daemon = on;
}
return this;
}
/**
* 是否为守护线程
*
* @return 是否为守护线程
*/
public boolean isDeamon() {
return this.daemon;
}
/**
* 是否支持秒匹配
*
* @return true
使用,false
不使用
*/
public boolean isMatchSecond() {
return this.matchSecond;
}
/**
* 设置是否支持秒匹配,默认不使用
*
* @param isMatchSecond true
支持,false
不支持
* @return this
*/
public Scheduler setMatchSecond(boolean isMatchSecond) {
this.matchSecond = isMatchSecond;
return this;
}
/**
* 增加监听器
*
* @param listener {@link TaskListener}
* @return this
*/
public Scheduler addListener(TaskListener listener) {
this.listenerManager.addListener(listener);
return this;
}
/**
* 移除监听器
*
* @param listener {@link TaskListener}
* @return this
*/
public Scheduler removeListener(TaskListener listener) {
this.listenerManager.removeListener(listener);
return this;
}
/**
* 批量加入配置文件中的定时任务
* 配置文件格式为: xxx.xxx.xxx.Class.method = * * * * *
*
* @param cronSetting 定时任务设置文件
* @return this
*/
public Scheduler schedule(Setting cronSetting) {
if (CollectionUtil.isNotEmpty(cronSetting)) {
String group;
for (Entry> groupedEntry : cronSetting.getGroupedMap().entrySet()) {
group = groupedEntry.getKey();
for (Entry entry : groupedEntry.getValue().entrySet()) {
String jobClass = entry.getKey();
if (StrUtil.isNotBlank(group)) {
jobClass = group + CharUtil.DOT + jobClass;
}
final String pattern = entry.getValue();
StaticLog.debug("Load job: {} {}", pattern, jobClass);
try {
schedule(pattern, new InvokeTask(jobClass));
} catch (Exception e) {
throw new CronException(e, "Schedule [{}] [{}] error!", pattern, jobClass);
}
}
}
}
return this;
}
/**
* 新增Task,使用随机UUID
*
* @param pattern {@link CronPattern}对应的String表达式
* @param task {@link Runnable}
* @return ID
*/
public String schedule(String pattern, Runnable task) {
return schedule(pattern, new RunnableTask(task));
}
/**
* 新增Task,使用随机UUID
*
* @param pattern {@link CronPattern}对应的String表达式
* @param task {@link Task}
* @return ID
*/
public String schedule(String pattern, Task task) {
String id = UUID.randomUUID().toString();
schedule(id, pattern, task);
return id;
}
/**
* 新增Task
*
* @param id ID,为每一个Task定义一个ID
* @param pattern {@link CronPattern}对应的String表达式
* @param task {@link Runnable}
* @return this
*/
public Scheduler schedule(String id, String pattern, Runnable task) {
return schedule(id, new CronPattern(pattern), new RunnableTask(task));
}
/**
* 新增Task
*
* @param id ID,为每一个Task定义一个ID
* @param pattern {@link CronPattern}对应的String表达式
* @param task {@link Task}
* @return this
*/
public Scheduler schedule(String id, String pattern, Task task) {
return schedule(id, new CronPattern(pattern), task);
}
/**
* 新增Task
*
* @param id ID,为每一个Task定义一个ID
* @param pattern {@link CronPattern}
* @param task {@link Task}
* @return this
*/
public Scheduler schedule(String id, CronPattern pattern, Task task) {
taskTable.add(id, pattern, task);
return this;
}
/**
* 移除Task
*
* @param id Task的ID
* @return this
*/
public Scheduler deSchedule(String id) {
this.taskTable.remove(id);
return this;
}
/**
* 更新Task执行的时间规则
*
* @param id Task的ID
* @param pattern {@link CronPattern}
* @return this
*/
public Scheduler updatePattern(String id, CronPattern pattern) {
this.taskTable.updatePattern(id, pattern);
return this;
}
/**
* 获得指定id的{@link CronPattern}
*
* @param id ID
* @return {@link CronPattern}
*/
public CronPattern getPattern(String id) {
return this.taskTable.getPattern(id);
}
/**
* 获得指定id的{@link Task}
*
* @param id ID
* @return {@link Task}
*/
public Task getTask(String id) {
return this.taskTable.getTask(id);
}
/**
* 是否无任务
*
* @return true表示无任务
*/
public boolean isEmpty() {
return this.taskTable.isEmpty();
}
/**
* 当前任务数
*
* @return 当前任务数
*/
public int size() {
return this.taskTable.size();
}
/**
* 清空任务表
*
* @return this
*/
public Scheduler clear() {
this.taskTable = new TaskTable(this);
return this;
}
/**
* @return 是否已经启动
*/
public boolean isStarted() {
return this.started;
}
/**
* 启动
*
* @param isDaemon 是否以守护线程方式启动,如果为true,则在调用{@link #stop()}方法后执行的定时任务立即结束,否则等待执行完毕才结束。
* @return this
*/
public Scheduler start(boolean isDaemon) {
this.daemon = isDaemon;
return start();
}
/**
* 启动
*
* @return this
*/
public Scheduler start() {
synchronized (lock) {
if (this.started) {
throw new CronException("Schedule is started!");
}
// 无界线程池,确保每一个需要执行的线程都可以及时运行,同时复用已有现成避免线程重复创建
this.threadExecutor = ExecutorBuilder.create().useSynchronousQueue().setThreadFactory(
ThreadFactoryBuilder.create().setNamePrefix("basetool-cron-").setDaemon(this.daemon).build()
).build();
this.taskLauncherManager = new TaskLauncherManager(this);
this.taskExecutorManager = new TaskExecutorManager(this);
// Start CronTimer
timer = new CronTimer(this);
timer.setDaemon(this.daemon);
timer.start();
this.started = true;
}
return this;
}
/**
* 停止定时任务
* 此方法调用后会将定时器进程立即结束,如果为守护线程模式,则正在执行的作业也会自动结束,否则作业线程将在执行完成后结束。
* 此方法并不会清除任务表中的任务,请调用{@link #clear()} 方法清空任务或者使用{@link #stop(boolean)}方法可选是否清空
*
* @return this
*/
public Scheduler stop() {
return stop(false);
}
/**
* 停止定时任务
* 此方法调用后会将定时器进程立即结束,如果为守护线程模式,则正在执行的作业也会自动结束,否则作业线程将在执行完成后结束。
*
* @param clearTasks 是否清空任务表
* @return this
*/
public Scheduler stop(boolean clearTasks) {
synchronized (lock) {
if (!started) {
throw new IllegalStateException("Scheduler not started !");
}
// 停止CronTimer
this.timer.stopTimer();
this.timer = null;
//停止线程池
this.threadExecutor.shutdown();
this.threadExecutor = null;
//可选是否清空任务表
if (clearTasks) {
clear();
}
// 修改标志
started = false;
}
return this;
}
}