背景
在项目中有个需求,在程序启动时根据配置文件中的状态值判断是否需要加载定时器定时调用远程服务。在之前的项目中基本都是使用基于Springboot框架提供的@EnableScheduling注解完成定时任务需求,而此次项目中并未使用spring等框架。所以这次将使用JDK自带的类库实现该需求
- java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。Timer执行任务时只是创建了单个线程。比如每隔1秒执行一次任务,中间有个长任务执行时间超过5秒,那么在上一个任务执行完成时,会快速执行4次或者丢失任务,一般用的较少
- java.util.concurrent.ScheduledExecutorService类,这个是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
基于上述,采用ScheduledExecutorService实现定时任务
具体实现方案如下
- 首先我需要有一个实现具体任务的类
public class UpdateConfigTask implements Runnable {
private EcgServerRequest ecgServerRequest;
private ConfigureEntity entity;
@Override
public void run() {
//判断是否内网,如果不是则退出
boolean nodeReachable = IPUtils.isNodeReachable("ecgnetwork-api.medwings.cn");
if (!nodeReachable) {
log.info("当前不是外网,拒绝请求执行");
return;
}
String deviceId = entity.getDeviceId();
//请求远程config内容
JSONObject jsonObject = ecgServerRequest.getGatewayConfigByDeviceId(deviceId);
String configFilePath = "config/configure.properties";
//判断文件是否有改动
boolean isUpdate = ConfigUtils.compareConfigContent(configFilePath,jsonObject);
if (!isUpdate) {
//有变化时需要更新
ConfigUtils.generateConfigurationFile(jsonObject, configFilePath);
}
}
private UpdateConfigTask() {
}
public UpdateConfigTask(EcgServerRequest serverRequest, ConfigureEntity entity) {
this.ecgServerRequest = serverRequest;
this.entity = entity;
}
}
- 我还需要一个管理任务的类,里面包括添加、删除、启动的方法
public class TaskManager {
private ScheduledExecutorService scheduler;
private List<Runnable> tasks;
public TaskManager() {
scheduler = Executors.newScheduledThreadPool(10);
tasks = new ArrayList<>();
}
public void addTask(Runnable task, long delay, long period) {
tasks.add(task);
//这里的意思是指固定的频率来执行某项计划,也就是说它不受计划执行时间的影响。到时间,它就执行
//参数是任务实例、初始化延时即首次执行的延时时间、两次开始执行最小间隔时间即定时执行的间隔时间、计时单位
scheduler.scheduleAtFixedRate(task, delay, period, TimeUnit.MILLISECONDS);
//它还有一种策略,按照相对固定频率来执行,相对是相对任务的。即无论某个任务执行多长时间,等执行完了,再延迟指定的时间执行下一次任务,它受上一次计划执行时间的影响
//scheduler.scheduleWithFixedDelay(task, delay, period, TimeUnit.MILLISECONDS)
}
public void removeTask(Runnable task) {
tasks.remove(task);
}
public void startAllTasks() {
for (Runnable task : tasks) {
//执行
scheduler.execute(task);
}
}
}
3. 使用