基于Mongodb分布式锁简单实现,解决定时任务并发执行问题
前言
我们日常开发过程,会有一些定时任务的代码来统计一些系统运行数据,但是我们应用有需要部署多个实例,传统的通过配置文件来控制定时任务是否启动又太过繁琐,而且还经常出错,导致一些异常数据的产生
网上有很多分布式锁的实现方案,基于redis、zk、等有很多,但是我的就是一个用了mysql和mongo的小应用,不准备引入其他三方中间件来解决这个问题,撸一个简单的分布式锁来解决定时任务并发执行的问题,加锁操作的原子性和防死锁也都要支持,这里我使用mongodb写了AllInOne的工具类
All in one Code
先上代码
@Component
@Slf4j
public class MongoDBLock {
private static final int DEFAULT_LOCK_TIMEOUT = 30;//锁的默认超时时间,单位秒
private MongoTemplate mongoTemplate;
private int lockTimeout;
public MongoDBLock(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
this.lockTimeout = DEFAULT_LOCK_TIMEOUT;
}
/**
* 尝试获取分布式锁
*
* @param lockKey 锁的key
* @return true:获取锁成功,false:获取锁失败
*/
private boolean acquireLock(String lockKey) {
LockDocument document = new LockDocument();
document.setId(lockKey);
document.setExpireAt(Instant.ofEpochMilli(Instant.now().toEpochMilli() + lockTimeout * 1000));
try {
mongoTemplate.insert(document);
return true;
} catch (Exception e) {
}
return false;
}
/**
* 释放分布式锁
*
* @param lockKey 锁的key
*/
private void releaseLock(String lockKey) {
Query query = new Query(Criteria.where("key").is(lockKey));
mongoTemplate.remove(query, LockDocument.class);
log.info("程序执行成功,释放分布式锁,lockKey:{}",lockKey);
}
/**
* 分布式锁入口方法,参数lockName为锁的名称,lockKey为需要加锁的key,执行完成后自动释放锁
*
* @param lockKey
* @param task
* @param <T>
* @throws Exception
*/
public <T> void executeWithLock(String lockKey, ITask<T> task) throws Exception {
boolean locked = acquireLock(lockKey);
if (locked) {
log.info("获取分布式锁成功,lockKey:{}",lockKey);
try {
task.execute();
} finally {
releaseLock(lockKey);
}
} else {
log.warn("获取分布式锁失败,lockKey:{}", lockKey);
throw new AppException("获取分布式锁失败!");
}
}
@Data
@Document(collection = "lock_collection")
static class LockDocument {
@Id
private String id;
@Indexed(expireAfterSeconds = DEFAULT_LOCK_TIMEOUT)
private Instant expireAt;
}
@FunctionalInterface
public interface ITask<T> {
T execute() throws Exception;
}
}
调用示例
@Resource
MongoDBLock mongoDBLock;
mongoDBLock.executeWithLock("key", () -> {
// do some thing
return null;
});
原理
- 使用key作为主键,利用mongodb的insert原子性保障LockDocument不会重复插入
- LockDocument中expireAt字段利用的mongodb索引过期机制,解决死锁问题,这里设置超时时间是30秒,并在执行完成之后会主动释放锁
基于Mongodb分布式锁简单实现,解决定时任务并发执行问题的更多相关文章
- RedLock.Net - 基于Redis分布式锁的开源实现
工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...
- ZooKeeper分布式锁简单实践
ZooKeeper分布式锁简单实践 在分布式解决方案中,Zookeeper是一个分布式协调工具.当多个JVM客户端,同时在ZooKeeper上创建相同的一个临时节点,因为临时节点路径是保证唯一,只要谁 ...
- c# 基于redis分布式锁
在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量. 而同步的本质是通过锁来实现的.为了实现多个线程在 ...
- 基于Redis分布式锁(获取锁及解锁)
目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性( ...
- 基于redis分布式锁实现“秒杀”
转载:http://blog.5ibc.net/p/28883.html 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓“秒杀”的基本思路. 业务场 ...
- 基于redis分布式锁实现“秒杀”(转载)
转载:http://blog.csdn.net/u010359884/article/details/50310387 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的de ...
- 基于 Redis 分布式锁
1.主流分布式锁实现方案 基于数据库实现分布式锁 基于缓存(redis 等) 基于 Zookeeper 2.根据实现方式分类 : 类 CAS 自旋式分布式锁:询问的方式,类似 java 并发编程中的线 ...
- 基于Redis分布式锁的正确打开方式
分布式锁是在分布式环境下(多个JVM进程)控制多个客户端对某一资源的同步访问的一种实现,与之相对应的是线程锁,线程锁控制的是同一个JVM进程内多个线程之间的同步.分布式锁的一般实现方法是在应用服务器之 ...
- zookeeper分布式锁简单实现(JavaApi)
1.创建会话连接 package com.karat.cn.zookeeperAchieveLock.javaapilock; import org.apache.zookeeper.WatchedE ...
- spring的@Scheduled定时任务,同一时间段的定时任务只会执行一个,其余的会被阻塞,@Scheduled注解定时任务并发执行解决办法,即多线程运行定时任务
原文:https://blog.csdn.net/qq_35937303/article/details/88851064 现有两个定时任务 @Component("aa") pu ...
随机推荐
- L02.从图灵机到通用计算机
将程序载入到内存(存储器)中,用一个指针指向它, 再载入到cpu(控制器)中进行解释执行 *(取指执行,产生结果) 取指执行 = 控制器从存储器中取出数据后,分析指令,运算器执行逻辑运算. PC= ...
- springboot后端接收不到前端传来的表单值
为啥接收不到 因为传来的字段值太大了,springboot默认启动依赖tomcat,tomcat默认接收表单值最大为2MB,将server.tomcat.max-http-form-post-size ...
- 我亲自整理的Tampermonkey(以下简称tm)v4.13.6136的编辑器按键映射(基于联想笔记本键盘+win10+火狐浏览器企业版)
警告:你可以对该随笔内容进行转载,但必须写明其来源网址,以及其作者是博客园的zqdlly,否则后果自负!不要小看了我,我一定会让你付出你应得的成本. 0. 家喻户晓的 键 原生comment myMe ...
- windows监控web程序连接数
运行: win+R->perfmon.msc 右键,添加计数器 选择webservice中的current connection选项,再选中对应实例即可~
- Docker-界面化
docker-ui docker-ui只能便于我们查看系统的相关信息,镜像或者容器.在界面上做简单的处理,可处理单机版Docker. docker pull uifd/ui-for-docker do ...
- Hyperf安装
转载网址: https://www.cnblogs.com/lyc94620/p/12821723.html
- Windows 任务栏透明 居中
任务栏设置 任务栏居中 由于windows默认的程序是从左往右显示,看着可能有一点不舒服,当然如果使用习惯的话,忽然居中,可能更不舒服 首先搜索字符映射表 点击字符映设表中第五行的空白字符,选择进行复 ...
- 【QCustomPlot】简介
说明 使用 QCustomPlot 绘图库辅助开发时整理的学习笔记. 目录 说明 1. 库简介 2. 库的官网链接 3. 库的帮助文档 4. 库的下载地址 5. 库的版本号说明 6. 库的 Git 地 ...
- Java笔记第十二弹
Lambda表达式的标准格式 三要素:形式参数.箭头.代码块 格式:(形式参数)->(代码块) 形式参数:如果有多个参数,参数之间用逗号隔开:如果没有参数,留空即可 ->代表指向动作 La ...
- 使用float进行比较问题处理
float compare Abstract 使用float数据进行精确计算和比较,可能由于精度问题导致程序逻辑异常. Explanation 使用float数据进行比较,计算机表达double和fl ...