redis分布式锁的实现原理实例分析
发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,这篇文章主要介绍了redis分布式锁的实现原理实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇redis分布式锁的实现原理实例分析文章都会有所收获,下面我们一起来看
千家信息网最后更新 2025年02月04日redis分布式锁的实现原理实例分析
这篇文章主要介绍了redis分布式锁的实现原理实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇redis分布式锁的实现原理实例分析文章都会有所收获,下面我们一起来看看吧。
首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
1.互斥性。在任意时刻,只有一个客户端能持有锁。
2.不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
3.具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
4.解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
下边是代码实现,首先我们要通过Maven引入Jedis
开源组件,在pom.xml
文件加入下面的代码:
org.springframework.boot spring-boot-starter-data-redis redis.clients jedis 3.1.0
分布式锁实现代码,DistributedLock.java
import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;import redis.clients.jedis.Transaction;import redis.clients.jedis.exceptions.JedisException;import java.util.List;import java.util.UUID;/** * @author swadian * @date 2022/3/4 * @Version 1.0 * @describetion Redis分布式锁原理 */public class DistributedLock { //redis连接池 private static JedisPool jedisPool; static { JedisPoolConfig config = new JedisPoolConfig(); // 设置最大连接数 config.setMaxTotal(200); // 设置最大空闲数 config.setMaxIdle(8); // 设置最大等待时间 config.setMaxWaitMillis(1000 * 100); // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的 config.setTestOnBorrow(true); jedisPool = new JedisPool(config, "192.168.3.27", 6379, 3000); } /** * 加锁 * @param lockName 锁的key * @param acquireTimeout 获取锁的超时时间 * @param timeout 锁的超时时间 * @return 锁标识 * Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。 * 设置成功,返回 1 。 设置失败,返回 0 。 */ public String lockWithTimeout(String lockName, long acquireTimeout, long timeout) { Jedis jedis = null; String retIdentifier = null; try { // 获取连接 jedis = jedisPool.getResource(); // value值->随机生成一个String String identifier = UUID.randomUUID().toString(); // key值->即锁名 String lockKey = "lock:" + lockName; // 超时时间->上锁后超过此时间则自动释放锁 毫秒转成->秒 int lockExpire = (int) (timeout / 1000); // 获取锁的超时时间->超过这个时间则放弃获取锁 long end = System.currentTimeMillis() + acquireTimeout; while (System.currentTimeMillis() < end) { //在获取锁时间内 if (jedis.setnx(lockKey, identifier) == 1) {//关键:设置锁 jedis.expire(lockKey, lockExpire); // 返回value值,用于释放锁时间确认 retIdentifier = identifier; return retIdentifier; } // ttl以秒为单位返回 key 的剩余过期时间,返回-1代表key没有设置超时时间,为key设置一个超时时间 if (jedis.ttl(lockKey) == -1) { jedis.expire(lockKey, lockExpire); } try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } catch (JedisException e) { e.printStackTrace(); } finally { if (jedis != null) { jedis.close(); } } return retIdentifier; } /** * 释放锁 * @param lockName 锁的key * @param identifier 释放锁的标识 * @return */ public boolean releaseLock(String lockName, String identifier) { Jedis jedis = null; String lockKey = "lock:" + lockName; boolean retFlag = false; try { jedis = jedisPool.getResource(); while (true) { // 监视lock,准备开始redis事务 jedis.watch(lockKey); // 通过前面返回的value值判断是不是该锁,若是该锁,则删除,释放锁 if (identifier.equals(jedis.get(lockKey))) { Transaction transaction = jedis.multi();//开启redis事务 transaction.del(lockKey); List
为了验证它,我们创建SkillService.java业务类
import lombok.extern.slf4j.Slf4j;@Slf4jpublic class SkillService { final DistributedLock lock = new DistributedLock(); public static final String LOCK_KEY = "lock_resource"; int n = 500; /** * 线程业务方法 */ public void seckill() { // 返回锁的value值,供释放锁时候进行判断 String identifier = lock.lockWithTimeout(LOCK_KEY, 5000, 1000); log.info("线程:"+Thread.currentThread().getName() + "获得了锁"); log.info("剩余数量:{}",--n); lock.releaseLock(LOCK_KEY, identifier); }}
如果找不到@Slf4j日志,在pom.xml
文件加入下面的代码:
org.projectlombok lombok
编辑一个测试类TestLock.java
/** * @author swadian * @date 2022/3/4 * @Version 1.0 */public class TestLock { public static void main(String[] args) { SkillService service = new SkillService(); for (int i = 10; i < 60; i++) { //开50个线程 SkillThread skillThread = new SkillThread(service, "skillThread->" + i); skillThread.start(); } }}class SkillThread extends Thread { private SkillService skillService; public SkillThread(SkillService skillService, String skillThreadName) { super(skillThreadName); this.skillService = skillService; } @Override public void run() { skillService.seckill(); }}
测试结果显示,加锁后剩余数量全部是顺序串行的,499,498,497...
我们修改SkillService.java业务类,注释掉加锁逻辑
@Slf4jpublic class SkillService { final DistributedLock lock = new DistributedLock(); public static final String LOCK_KEY = "lock_resource"; int n = 500; /** * 线程业务方法 */ public void seckill() { // 返回锁的value值,供释放锁时候进行判断 //String identifier = lock.lockWithTimeout(LOCK_KEY, 5000, 1000); log.info("线程:"+Thread.currentThread().getName() + "获得了锁"); log.info("剩余数量:{}",--n); //lock.releaseLock(LOCK_KEY, identifier); }}
重新执行测试,注释掉加锁逻辑后,剩余数量全部是乱序的,472,454,452...
关于"redis分布式锁的实现原理实例分析"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"redis分布式锁的实现原理实例分析"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。
时间
分布式
实例
客户
客户端
原理
剩余
实例分析
分析
业务
代码
数量
线程
最大
事务
知识
测试
成功
内容
得了
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
数据库 例子下载
第六届广东省网络安全博览会
怎么查看数据库对卷的管理方式
数据库使用技巧和方法
人员组织架构数据库设计
连上网无法连接到服务器
数据库基本操作视频
下列属于期刊数据库的是
延庆区信息网络技术推广
查看和选择数据库的代码
苹果怎样与服务器建立安全的连接
管理服务器app
无法连接到anydesk服务器
各公司网络安全活动形式多样
文件服务器为啥有些文件不能存
青少年网络安全插画海报
数据库大型设计
链路数据库表
在线代理 代理服务器
数据库 设计工具
举例说明数据库查询
数据库怎么找蛋白信息
学生网络技术开发项目
华为acs服务器
进化网络安全手抄报图片
pe 支持服务器
软件开发外包项目管理办法
软件开发中的接口
网络技术基础定义分类
服务好的软件开发公司有哪些