Java使用定时任务开始-结束活动

        有一种场景,比如抢购活动,活动的开始肯定不是到点后手动点击开始按钮的,而是通过配置活动开始时间和结束时间,然后开启定时任务,通过定时任务来控制活动的开始和结束。
1. 活动上架--触发定时任务的开启
@Override
@Transactional(rollbackFor = Exception.class)
public void publishIntegralActivity(List<Long> idList) {// 修改上架状态String accountName = SessionUtils.getAccountNameSession();integralActivityDao.updatePublishStatus(idList, PublishStatusEnum.PUBLISH_YES.getCode(), accountName);// 活动开始定时任务for (Long id : idList) {IntegralActivity integralActivity = integralActivityDao.getById(id);integralActivityCronService.addStartCron(id, integralActivity.getStartTime());}
}
2. 开启活动开始定时任务
public void addStartCron(long id, Date startTime) {long millSecond = startTime.getTime() - System.currentTimeMillis();ScheduledFuture<?> scheduledFuture = scheduleExecutor.schedule(new Runnable() {@Overridepublic void run() {log.debug("integral activity[id=" + id + "] start cron begin execute");String key = RedisConstant.INTEGRAL_ACTIVITY_CRON + ":" + ACTIVITY_START_CRON_PREFX + id;String value = UUID.randomUUID().toString().replace("-", "");if (!getExecuteLock(key, value)) {return;}try {IntegralActivityQueryDto queryDto = new IntegralActivityQueryDto();queryDto.setId(id);List<IntegralActivity> activityList = integralActivityDao.getActivityList(queryDto);if (CollectionUtils.isEmpty(activityList) ||!ActivityStatusEnum.NOT_START.getCode().equals(activityList.get(0).getActivityStatus()) ||startTime.getTime() != activityList.get(0).getStartTime().getTime()) {log.warn("when execute start cron, integral activity[id=" + id + "] not exists or status not match");lockUtils.unLock(key, value);return;}// 更改活动状态integralActivityDao.updateActivityStatus(Lists.newArrayList(id), ActivityStatusEnum.IN_PROGRESS.getCode(), null, null, activityList.get(0).getEndTime());// 清除活动结束定时任务clearCronById(ACTIVITY_END_CRON_PREFX + id);// 添加活动结束定时任务addEndCron(id, activityList.get(0).getEndTime());lockUtils.unLock(key, value);} catch (Exception e) {log.error("integral activity[id=" + id + "] start error, retry", e);lockUtils.unLock(key, value);addStartCron(id, startTime);}}}, millSecond, TimeUnit.MILLISECONDS);// 加入任务currentCronMap.put(ACTIVITY_START_CRON_PREFX + id, scheduledFuture);
}
3. 开启定时任务时要加锁,防止并发请求
private boolean getExecuteLock(String key, String value) {for (int i = 1; i <= 5; i++) {try {if (lockUtils.getLock(key, value, 10 * 60 * 1000)) {return true;}} catch (Exception e) {log.warn("redis lock[key=" + key + "] get error, continue");}}return false;
}
4. 开启活动结束定时任务
private void addEndCron(long id, Date endTime) {long millSecond = endTime.getTime() - System.currentTimeMillis();log.debug("integral activity[id=" + id + "] end cron begin execute");ScheduledFuture<?> scheduledFuture = scheduleExecutor.schedule(new Runnable() {@Overridepublic void run() {try {IntegralActivityQueryDto queryDto = new IntegralActivityQueryDto();queryDto.setId(id);List<IntegralActivity> activityList = integralActivityDao.getActivityList(queryDto);if (CollectionUtils.isEmpty(activityList) ||!ActivityStatusEnum.IN_PROGRESS.getCode().equals(activityList.get(0).getActivityStatus()) ||endTime.getTime() != activityList.get(0).getEndTime().getTime()) {return;}// 更改活动状态integralActivityDao.updateActivityStatus(Lists.newArrayList(id), ActivityStatusEnum.FINISHED.getCode(), null, null, new Date());// 更改上架状态integralActivityDao.updatePublishStatus(Lists.newArrayList(id), PublishStatusEnum.PUBLISH_NO.getCode(), null);} catch (Exception e) {log.error("integral activity[id=" + id + "] end error, retry", e);addEndCron(id, endTime);}}}, millSecond, TimeUnit.MILLISECONDS);// 加入任务currentCronMap.put(ACTIVITY_END_CRON_PREFX + id, scheduledFuture);
}
5.  活动下架
@Override
@Transactional(rollbackFor = Exception.class)
public void offIntegralActivity(List<Long> idList) {String accountName = SessionUtils.getAccountNameSession();integralActivityDao.updateActivityStatus(idList, ActivityStatusEnum.EARLY_STOP.getCode(), null, accountName, new Date());integralActivityDao.updatePublishStatus(idList, PublishStatusEnum.PUBLISH_NO.getCode(), accountName);// 活动结束定时任务for (Long id : idList) {integralActivityCronService.clearActivityCron(id);}
}
6. 活动下架后要清除定时任务
public void clearActivityCron(long id) {this.clearCronById(ACTIVITY_START_CRON_PREFX + id);this.clearCronById(ACTIVITY_END_CRON_PREFX + id);
}@SuppressWarnings("rawtypes")
private void clearCronById(String cronId) {if (currentCronMap.get(cronId) == null) {log.debug("cron[id=" + cronId + "] not exists");}Future future = currentCronMap.get(cronId);if (null != future && !future.isDone()) {future.cancel(true); // 正在运行是否干扰}currentCronMap.remove(cronId);
}
7. 程序启动时开启所有活动的定时任务
@Component
@Slf4j
public class InitIntegralActivityCron implements CommandLineRunner {@Autowiredprivate LockUtils lockUtils;@Autowiredprivate IntegralActivityCronService integralActivityCronService;@Overridepublic void run(String... args) throws Exception {// 初始化积分活动定时任务String key = RedisConstant.LOAD_INTEGRAL_ACTIVITY_CRON;String value = UUID.randomUUID().toString().replace("-", "");if (!lockUtils.getLock(key, value, 30 * 60 * 1000)) {log.info("integral activity cron load lock get failed, return!!!");return;}try {if (!integralActivityCronService.createAllActivityCron()) {lockUtils.unLock(key, value);log.error("partial integral activity cron load error, system will exit");System.exit(0);}} catch (Exception e) {log.error("integral activity cron load error, system will exit", e);lockUtils.unLock(key, value);System.exit(0);}}
}
@Override
public boolean createAllActivityCron() {boolean isAllSuccess = true;// 是否都创建成功List<String> activityStatusList = new ArrayList<String>();activityStatusList.add(ActivityStatusEnum.NOT_START.getCode());activityStatusList.add(ActivityStatusEnum.IN_PROGRESS.getCode());IntegralActivityQueryDto queryDto = new IntegralActivityQueryDto();queryDto.setActivityStatusList(activityStatusList);queryDto.setPublishStatusList(Lists.newArrayList(PublishStatusEnum.PUBLISH_YES.getCode()));List<IntegralActivity> activityList = integralActivityDao.getActivityList(queryDto);if (CollectionUtils.isNotEmpty(activityList)) {for (IntegralActivity integralActivity : activityList) {long id = integralActivity.getId();try {if (ActivityStatusEnum.NOT_START.getCode().equals(integralActivity.getActivityStatus())) {this.addStartCron(id, integralActivity.getStartTime());} else {this.addEndCron(id, integralActivity.getEndTime());}} catch (Exception e) {isAllSuccess = false;log.error("integral activity[id=" + id + "] cron create error", e);}}}log.info("create integral activity cron end, activity count =" + activityList.size() + " " + (isAllSuccess ? "all success" : "partial success"));return isAllSuccess;
}

上面是定时任务的完整流程,下面补充完整代码:

1. 定时任务完整代码
@Service
@Slf4j
public class IntegralActivityCronServiceImpl implements IntegralActivityCronService {// 执行定时对象池private ScheduledExecutorService scheduleExecutor = Executors.newScheduledThreadPool(2);// 所有的定时任务@SuppressWarnings("rawtypes")private static Map<String, Future> currentCronMap = new HashMap<String, Future>();/*** 活动开始定时任务ID前缀*/private static final String ACTIVITY_START_CRON_PREFX = "ACTIVITY_START:";/*** 活动结束定时任务ID前缀*/private static final String ACTIVITY_END_CRON_PREFX = "ACTIVITY_END:";@Autowiredprivate IntegralActivityDao integralActivityDao;@Autowiredprivate LockUtils lockUtils;@Overridepublic boolean createAllActivityCron() {boolean isAllSuccess = true;// 是否都创建成功List<String> activityStatusList = new ArrayList<String>();activityStatusList.add(ActivityStatusEnum.NOT_START.getCode());activityStatusList.add(ActivityStatusEnum.IN_PROGRESS.getCode());IntegralActivityQueryDto queryDto = new IntegralActivityQueryDto();queryDto.setActivityStatusList(activityStatusList);queryDto.setPublishStatusList(Lists.newArrayList(PublishStatusEnum.PUBLISH_YES.getCode()));List<IntegralActivity> activityList = integralActivityDao.getActivityList(queryDto);if (CollectionUtils.isNotEmpty(activityList)) {for (IntegralActivity integralActivity : activityList) {long id = integralActivity.getId();try {if (ActivityStatusEnum.NOT_START.getCode().equals(integralActivity.getActivityStatus())) {this.addStartCron(id, integralActivity.getStartTime());} else {this.addEndCron(id, integralActivity.getEndTime());}} catch (Exception e) {isAllSuccess = false;log.error("integral activity[id=" + id + "] cron create error", e);}}}log.info("create integral activity cron end, activity count =" + activityList.size() + " " + (isAllSuccess ? "all success" : "partial success"));return isAllSuccess;}/*** 添加启动定时任务* * @param id* @param startTime*/public void addStartCron(long id, Date startTime) {long millSecond = startTime.getTime() - System.currentTimeMillis();ScheduledFuture<?> scheduledFuture = scheduleExecutor.schedule(new Runnable() {@Overridepublic void run() {log.debug("integral activity[id=" + id + "] start cron begin execute");String key = RedisConstant.INTEGRAL_ACTIVITY_CRON + ":" + ACTIVITY_START_CRON_PREFX + id;String value = UUID.randomUUID().toString().replace("-", "");if (!getExecuteLock(key, value)) {return;}try {IntegralActivityQueryDto queryDto = new IntegralActivityQueryDto();queryDto.setId(id);List<IntegralActivity> activityList = integralActivityDao.getActivityList(queryDto);if (CollectionUtils.isEmpty(activityList) ||!ActivityStatusEnum.NOT_START.getCode().equals(activityList.get(0).getActivityStatus()) ||startTime.getTime() != activityList.get(0).getStartTime().getTime()) {log.warn("when execute start cron, integral activity[id=" + id + "] not exists or status not match");lockUtils.unLock(key, value);return;}// 更改活动状态integralActivityDao.updateActivityStatus(Lists.newArrayList(id), ActivityStatusEnum.IN_PROGRESS.getCode(), null, null, activityList.get(0).getEndTime());// 清除活动结束定时任务clearCronById(ACTIVITY_END_CRON_PREFX + id);// 添加活动结束定时任务addEndCron(id, activityList.get(0).getEndTime());lockUtils.unLock(key, value);} catch (Exception e) {log.error("integral activity[id=" + id + "] start error, retry", e);lockUtils.unLock(key, value);addStartCron(id, startTime);}}}, millSecond, TimeUnit.MILLISECONDS);// 加入任务currentCronMap.put(ACTIVITY_START_CRON_PREFX + id, scheduledFuture);}/*** 添加结束定时任务** @param id* @param endTime*/private void addEndCron(long id, Date endTime) {long millSecond = endTime.getTime() - System.currentTimeMillis();log.debug("integral activity[id=" + id + "] end cron begin execute");ScheduledFuture<?> scheduledFuture = scheduleExecutor.schedule(new Runnable() {@Overridepublic void run() {try {IntegralActivityQueryDto queryDto = new IntegralActivityQueryDto();queryDto.setId(id);List<IntegralActivity> activityList = integralActivityDao.getActivityList(queryDto);if (CollectionUtils.isEmpty(activityList) ||!ActivityStatusEnum.IN_PROGRESS.getCode().equals(activityList.get(0).getActivityStatus()) ||endTime.getTime() != activityList.get(0).getEndTime().getTime()) {return;}// 更改活动状态integralActivityDao.updateActivityStatus(Lists.newArrayList(id), ActivityStatusEnum.FINISHED.getCode(), null, null, new Date());// 更改上架状态integralActivityDao.updatePublishStatus(Lists.newArrayList(id), PublishStatusEnum.PUBLISH_NO.getCode(), null);} catch (Exception e) {log.error("integral activity[id=" + id + "] end error, retry", e);addEndCron(id, endTime);}}}, millSecond, TimeUnit.MILLISECONDS);// 加入任务currentCronMap.put(ACTIVITY_END_CRON_PREFX + id, scheduledFuture);}/*** 清除活动定时任务* * @param id*/public void clearActivityCron(long id) {this.clearCronById(ACTIVITY_START_CRON_PREFX + id);this.clearCronById(ACTIVITY_END_CRON_PREFX + id);}/*** 通过id清除任务** @param cronId*/@SuppressWarnings("rawtypes")private void clearCronById(String cronId) {if (currentCronMap.get(cronId) == null) {log.debug("cron[id=" + cronId + "] not exists");}Future future = currentCronMap.get(cronId);if (null != future && !future.isDone()) {future.cancel(true); // 正在运行是否干扰}currentCronMap.remove(cronId);}/*** 获取活动执行锁** @param key* @param value* @return*/private boolean getExecuteLock(String key, String value) {for (int i = 1; i <= 5; i++) {try {if (lockUtils.getLock(key, value, 10 * 60 * 1000)) {return true;}} catch (Exception e) {log.warn("redis lock[key=" + key + "] get error, continue");}}return false;}
}
2. Redis工具类
@Component()
public class LockUtils {@Resourceprivate RedisTemplate<String, Object> redisTemplate;public LockUtils() {}public boolean getLock(String key) {return this.redisTemplate.opsForValue().setIfAbsent("lock_key_" + key, "lock_default_value", Duration.ofSeconds(60L));}public boolean getLock(String key, String value) {return this.redisTemplate.opsForValue().setIfAbsent("lock_key_" + key, value, Duration.ofSeconds(60L));}public boolean unLock(String key) {return this.redisTemplate.delete("lock_key_" + key);}public boolean unLock(String key, String value) {if (value == null) {return this.unLock(key);} else {return value.equals(this.redisTemplate.opsForValue().get("lock_key_" + key)) ? this.redisTemplate.delete("lock_key_" + key) : false;}}public boolean getLock(String key, long expireTime) {return this.redisTemplate.opsForValue().setIfAbsent("lock_key_" + key, "lock_default_value", expireTime, TimeUnit.MILLISECONDS);}public boolean getLock(String key, String value, long expireTime) {return this.redisTemplate.opsForValue().setIfAbsent("lock_key_" + key, value, expireTime, TimeUnit.MILLISECONDS);}
}
3. 活动状态枚举类
public enum ActivityStatusEnum {NOT_START("1", "未开始"),IN_PROGRESS("2", "进行中"),FINISHED("3", "已结束"),EARLY_STOP("4", "提前结束");private String code;private String value;private ActivityStatusEnum(String code, String value) {this.code = code;this.value = value;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}/*** 根据code获取value* @param code* @return*/public static String getValueByCode(String code) {if (StringUtils.isEmpty(code)) {return "";}for (ActivityStatusEnum item : ActivityStatusEnum.values()) {if (item.getCode().equals(code)) {return item.getValue();}}return "";}/*** 根据code获取value* @param code* @return*/public static String getCodeByValue(String value) {if (StringUtils.isEmpty(value)) {return "";}for (ActivityStatusEnum item : ActivityStatusEnum.values()) {if (item.getValue().equals(value)) {return item.getCode();}}return "";}
}

其它业务代码没有参考价值不再贴出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/50250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

yolov5使用flask部署至前端,实现照片\视频识别

初学yolo flask时&#xff0c;需要此功能&#xff0c;Csdn、Github、B站找到许多代码&#xff0c;效果并不满意。 近期&#xff0c;再度尝试&#xff0c;实现简单功能。 实现功能&#xff1a; 上传图片并识别,可以点击图片放大查看 上传视频并识别 识别后的文件下载功能 …

Windows电脑如何启动RTSP服务实现本地摄像头数据共享

技术背景 提起Windows共享本地摄像头&#xff0c;好多人想到的是通过ffmepg或vlc串流到服务器&#xff0c;实际上&#xff0c;用轻量级RTSP服务更简单&#xff0c;本文就介绍下&#xff0c;如何用大牛直播SDK的Windows轻量级RTSP服务&#xff0c;采集摄像头&#xff0c;生成本…

人工智能历史:从梦想到现实的变革之路

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Git 安装教程

1、登录git 官方网站&#xff1a;https://git-scm.com/ 点击左边的 Downloads 或者 右边标识的下载标志&#xff0c;它根据电脑操作系统自动匹配版本 Downloads for Windows 2、以 windows 为例下载对应版本 网络有时可能不大好&#xff0c;阿里镜像下载超快。 下载好以后&a…

Tensorflow中高维矩阵的乘法运算tf.matmul(tf.linalg.matmul)详悉

1.问题由来 在tensorflow框架下&#xff0c;经常会用到矩阵的乘法运算&#xff0c;特别是高&#xff08;多&#xff09;维的矩阵运算&#xff0c;在这些矩阵运算时&#xff0c;经常使用到其中的tf.matmul或tf.linalg.matmul等函数。但高维矩阵在内部怎么运算的&#xff1f;其内…

npm yarn pnpm的区别

‌npm, ‌yarn, 和 ‌pnpm 都是用于管理 ‌JavaScript 项目依赖的工具&#xff0c;但它们在设计理念、性能和功能上有显著的区别。 npm 是 Node.js 的官方包管理器&#xff0c;主要用于管理和分发 Node.js 的依赖。它支持语义版本控制&#xff0c;确保在不同环境中保持一致性&a…

【深度学习入门】安装conda/miniconda、所需包类、CUDA与conda/Miniconda间的关系

深度学习入门 须知 本教程跟随李沐老师课程随笔&#xff0c;课程链接点击此处。 CUDA和Anaconda的关系 CUDA Toolkit是由Nvidia官方提供的完整工具包&#xff0c;其中提供了Nvidia驱动程序、开发CUDA程序相关的开发工具包等。 Anaconda在安装Pytorch等会用到的CUDA的框架时…

【INTEL(ALTERA)】Quartus® Prime Pro Edition 软件 v24.2 中,哪些 Agilex™ 5 IP 功能的硬件验证有限?

目录 说明 解决方法 说明 如下表所示&#xff0c;Quartus Prime 专业版软件 24.2 版为 Agilex™ 5 IP 或功能提供有限的硬件支持。此外&#xff0c;设备的设备型号、比特流和固件尚未最终确定。 影响 Agilex™ 5 特定功能的已知问题可参阅 Agilex 5 知识库文章搜索。 解决…

【Air724UG】4G模块

目录 一、实物图 二、原理图 引脚定义 三、简介 基本原理 产品参数 UART1 蓝色指示灯 五、注意&#xff1a; 源文件下载 可访问底部联系方式也可前往电子校园网官网搜索关键词 关键词&#xff1a; Air724UG 一…

wpf中轮询显示图片

本文的需求是&#xff0c;在一个文件夹中&#xff0c;放一堆图片的集合&#xff0c;然后在wpf程序中&#xff0c;按照定时的方式&#xff0c;循序显示照片。 全部代码 1.声明一个PictureInfo类 namespace WpfApp1 {public class PictureInfo{public string? FileName { get; …

科技日报:华宇TAS应用中间件亮相2024政法智能化建设技术装备及成果展

近日&#xff0c;2024政法智能化建设技术装备及成果展在北京国家会议中心举行。成果展上&#xff0c;信创领域的华宇TAS应用中间件产品引人注目。 中间件是一种基础软件&#xff0c;在信息系统中处于应用运行支撑及连接的基础地位&#xff0c;是构建数字化转型基础设施的中坚力…

uni-app全局文件与常用API

文章目录 rpx响应式单位import导入css样式及scss变量用法与static目录import导入css样式uni.scss变量用法 pages.json页面路由globalStyle的属性pages设置页面路径及窗口表现tabBar设置底部菜单选项及iconfont图标 vite.config中安装插件unplugin-auto-import自动导入vue和unia…

探索Perl的奇妙世界:入门学习与实战指南

一、Perl语言概述 1.1 Perl的起源与发展 Perl&#xff08;Practical Extraction and Reporting Language&#xff09;是一种高级、解释型、动态编程语言&#xff0c;由Larry Wall于1987年发明。Perl的初衷是作为一种文本处理工具&#xff0c;帮助系统管理员在Unix系统中处理报…

Godot游戏制作 04平台设计

新建创景&#xff0c;添加AnimatableBody2D节点。 添加Sprite2D节点 拖动图片 剪裁图片&#xff0c;吸附模式&#xff1a;像素吸附 添加CollisionShape2D&#xff0c;设置实际形状为矩形 重命名AnimatableBody2D节点为Platform&#xff0c;保存场景&#xff0c;拖动platform场景…

STM32 | 看门狗IWDG喂狗实战

点击上方"蓝字"关注我们 01、实现功能 1、通过按键中断,让CPU执行往非法地址写入一个数据(往非法地址写入数据,系统会卡死) 非法地址:0xC0000000 02、看门狗头文件 #ifndef __IWDG_H#define __IWDG_H​#include "stm32f4xx.h"​​​void Iwdg_Init…

自动驾驶仿真前后端

自动驾驶仿真系统的开发涉及前端和后端两个主要方面&#xff0c;分别负责用户界面和仿真逻辑的实现。下面分别介绍自动驾驶仿真系统的前端和后端开发过程&#xff1a; ### 前端开发 前端开发主要关注用户界面的设计和交互&#xff0c;通常使用的技术包括图形用户界面&#xf…

数据库(MySQL)-视图、存储过程、触发器

一、视图 视图的定义、作用 视图是从一个或者几个基本表&#xff08;或视图&#xff09;导出的表。它与基本表不同&#xff0c;是一个虚表。但是视图只能用来查看表&#xff0c;不能做增删改查。 视图的作用&#xff1a;①简化查询 ②重写格式化数据 ③频繁访问数据库 ④过…

oracle 宽表设计

Oracle宽表设计主要涉及到数据库表或视图中字段&#xff08;列&#xff09;数量较多的情况。在Oracle 23c及以后的版本中&#xff0c;数据库表或视图中允许的最大列数已增加到4096&#xff0c;这为宽表设计提供了更大的灵活性。以下是对Oracle宽表设计的详细分析&#xff1a; …

Android 开发中px、dpi 和 dp三个单位的介绍

Android 开发中px、dpi 和 dp三个单位的介绍 在 Android 开发中&#xff0c;px、dpi 和 dp 是用来描述屏幕尺寸和密度的单位&#xff0c;它们在设计和开发中有着不同的作用和用途。 1. px&#xff08;像素&#xff09; 定义&#xff1a; px 表示屏幕上的一个像素点&#xff0c…

Git项目如何配置,如何上传至GitHub

Git项目配置并上传至GitHub的详细步骤如下&#xff1a; 一、准备工作 创建GitHub账号&#xff1a; 访问GitHub官网&#xff0c;点击“Sign up”注册新账号。填写相关信息&#xff0c;包括用户名、邮箱和密码&#xff0c;完成账号创建。安装Git客户端&#xff1a; 访问Git官网…