国外被动收入网站做的好的,网站建设电脑维修数据恢复,wordpress换到新服务器,太原做网站的网络公司延时任务与定时任务的区别
延时任务#xff0c;可以理解为定时任务的一种#xff0c;但是他们是有区别的。 延时任务#xff1a;将程序代码延时执行#xff0c;执行完毕#xff0c;即为结束。 定时任务#xff1a;周期性执行任务。代码执行完毕后#xff0c;并不意味着…延时任务与定时任务的区别
延时任务可以理解为定时任务的一种但是他们是有区别的。 延时任务将程序代码延时执行执行完毕即为结束。 定时任务周期性执行任务。代码执行完毕后并不意味着结束会根据定时的周期时间继续下次的执行。
如何做定时任务
之前做过一期的博客Redis做定时任务 但是是有错误的。我把redis的那个空间变动通知当成定时了其实他应该算是延时。。。。 那如何做呢
java自带的延时队列redis空间变动通知可使用定时任务的那种任务调度器做设置好时间执行一次然后关闭。……
实操
新的项目新的需求一个物联网那个项目。设备爆出警报来后用户可以设置忽略误报在多少时间内不在提示这个错误。 对应到数据上就是报警数据的[字段处理状态]修改为已处理就查不到报警信息了。但是忽略时间一到状态会自动改回未处理
刚开始我是想使用Redis来做的但是想使用redis就必须修改配置文件服务器不在我们手里修改不了这个方案被pass掉了。 然后我使用项目中自带的任务调度器xxl-job开源的任务调度器跟Quartz一样的东西自己计算cron表达式添加任务启动任务然后执行修改方法关闭任务。但是么最后。。。被领导臭骂了一顿。说是用延时队列来做。。。
创建操作类 import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;import java.util.List;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;Data
NoArgsConstructor
AllArgsConstructor
public class DelayedAlarm implements Delayed {/*** 过期时间。这个时间一定是一个Date类型转成的*/private Long expireTime;/*** 集合ID*/private ListString alarmIds;/*** 是否过期。小于等于0的表示过期大于0的表示未过期其差值表示还有多少时间过期。* 这个我踩了一个大坑。我写的代码为啥就是不会延时执行* 因为这个方法表示还有多少时间过期一定是过期时间减去当前时间还剩下多少时间。* 而我直接unit.convert(expireTime,TimeUnit.MILLISECONDS)了* 因为只是做了一下时间的转换每次java调用这个方法判断还有多长时间过期一直是这个数所以他就一直延时。。。。* param unit 时间的单位* return 返回排序结果*/Overridepublic long getDelay(NotNull TimeUnit unit) {return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}/*** 排序方法。用于排序因为放进来的对象根据延时时间的大小不一定是排在后面的有可能是排在前面的。* param o 刚加入对象* return 返回排序结果*/Overridepublic int compareTo(NotNull Delayed o) {return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));}
}业务调用
//省略不重要的导入
public class AlarmServiceImpl {//省略其他不重要的注入。private final DelayQueueDelayedAlarm DELAY_QUEUE new DelayQueue();PostConstructpublic void updateAlarmStatusQueue() {//因为是本地缓存的队列重启服务会丢失需要重新查库重新添加队列ListAlarmInfo list alarmInfoMapper.getIgnoreAlarmList();list.forEach(entity - {long timeDiff System.currentTimeMillis() - entity.getAlarmStartTime().getTime();long expireTime entity.getIgnoreTime() * 1000L;if (expireTime timeDiff) {//当前忽略时间时间差expireTime expireTime - timeDiff;} else {expireTime 0;}DELAY_QUEUE.put(new DelayedAlarm(expireTime, Arrays.asList(entity.getId())));});//这个地方。等价于 ThreadPoolExecutor executorExecutors.newSingleThreadExecutor()。//阿里巴巴代码扫描总是飘黄我给改了一下。。ThreadPoolExecutor executor new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueueRunnable(),new DefaultThreadFactory(alarm_delaye_queue));executor.execute(new Thread(() - {while (true) {try {DelayedAlarm take DELAY_QUEUE.take();//获取id集合执行业务逻辑this.updateAlarmStatus(take.getAlarmIds());log.info(延时执行队列成功);} catch (Exception e) {//注意一定要捕获异常否则出现异常while循环就结束了。log.error(延时执行队列失败, e);}}}));}/*** 忽略误报时间到了自动修改警报信息状态已处理--未处理* param alarmIds 警报信息ID 集合* return*/public void updateAlarmStatus(ListString alarmIds) {ListAlarmInfo list new ArrayList();alarmIds.forEach(id - {//开始更新警报信息状态list.add(new AlarmInfo().setId(id).setStatus(UN_DISPOSED.getType()).setLastModifyUserId(userUtil.getUserId()));});//集成了mybaits-plus 插件我代码给删除了大家用的时候需要自己写Mapperthis.updateBatchById(list);log.info(延时执行修改报警信息状态成功:{},JSONObject.toJSONString(alarmIds));}/*** 将当前的忽略误报信息添加延时队列* param ids 警报信息ID 集合* param expireTime 过期时间*/public void handleIgnoreAlarm(ListString ids,Date expireTime) {//省略不重要的业务。。。。//添加队列DELAY_QUEUE.put(new DelayedAlarm(expireTime.getTime(), ids));}
}最后看一下执行结果