分布式锁

基于redis实现分布式锁思考几个问题???

synchronized锁为什么不能应用于分布式锁?

synchronized虽然能够解决同步问题,但是每次只有一个线程访问,并且synchronized锁属于JVM锁,仅适用于单点部署;然而分布式需要部署多台实例,属于不同的JVM线程对象

使用redis中setnx实现分布式锁。

//设置分布式锁
String lockKey = "product_001_key";
//语义:如何不存在则存入缓存中,且返回true;
//否则已存在,则返回false即加锁失败
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock");
if (!result) {//没有加锁成功,则返回提示等
}
try{}catch() {}finally{//释放锁stringRedisTemplate.delete(lockKey);
}

针对以上设置分布式锁思考一下问题?

1.如果突然服务器宕机,那么必然造成锁无法释放,即造成死锁?

解决方案:设置超时时间。

//设置分布式锁
String lockKey = "product_001_key";
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock");
//设置锁超时时间30s
stringRedisTemplate.expire(lockKey,30, TimeUnit.SECONDS);
if (!result) {//没有加锁成功,则返回提示等
}
try{}catch() {}finally{//释放锁stringRedisTemplate.delete(lockKey);
}

2.加锁和设置超时时间中间引起服务器宕机,则一样会导致死锁。

Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock");
//------服务器宕机,则超时时间未设置成功-------
//设置锁超时时间30s
stringRedisTemplate.expire(lockKey,30, TimeUnit.SECONDS);

解决方案:原子性操作,即同时加锁和设置超时时间;

即上面的代码合并成一句操作:

Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"product_001_lock", 30, TimeUnit.SECONDS)

3.思考超时时间设置是否合理呢?即线程执行时间和锁超时时间并非一致。

场景:假设设置加锁超时时间10s;

高并发场景下,线程A执行时间为15s,redis依据超时时间,将其线程A加的锁释放掉;然后线程B获取锁,并加锁成功,此时线程A执行结束,执行finally代码块就会将线程B加的锁释放。

解决方案:设置线程随机ID,释放锁时判断是否为当前线程加的锁,即使存在线程A因线程执行时间超时被动释放其锁,但至少保证当前超时线程不会释放其他线程加的锁。但是面对线程执行时间大于设置的超时时间,也是会存在并发问题。

String lockKey = "product_001";
String clientId = UUID.randomUUID().toString();
//设置超时时间,且加锁和设置线程ID
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,clientId, 30, TimeUnit.SECONDS)`if (!result) {//没有加锁成功,则返回提示等
}
try{}catch() {}finally{//释放锁:加锁线程ID和当前执行线程ID相同,才允许释放锁if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))){stringRedisTemplate.delete(lockKey);}
}

4.上面场景解决方案:加锁续命即续线程锁超时时间

解决方案:加锁成功时,开启一个后台线程,每隔10s(自定义)判断当前线程是否还持有锁,持有锁则再续命30s等

Redission实现分布式锁

实现原理流程:

         String lockKey = "product_001";//获取锁对象,并未加锁RLock redissonLock = redisson.getLock(lockKey);try {// **此时加锁**,实现锁续命功能redissonLock.lock();int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); if (stock > 0) {int realStock = stock - 1;stringRedisTemplate.opsForValue().set("stock", realStock + ""); System.out.println("扣减成功,剩余库存:" + realStock + "");} else {System.out.println("扣减失败,库存不足");}}finally {//释放锁redissonLock.unlock();}

总结

综上,设计实现分布式锁需要满足一下条件:

1.互斥性;在任意时刻,只有一个客户端能持有锁。

2.不能发生死锁;即使存在一个线程持有锁的期间崩溃而没有主动解锁,也能保证后续其他线程能加锁。

3.加锁和解锁必须是同一个线程。

基于redis实现分布式锁思考相关推荐

  1. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  2. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  3. 基于 Redis 的分布式锁到底安全吗?

    [完整版] 网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现 ...

  4. 基于Redis的分布式锁真的安全吗?

    说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...

  5. 基于Redis的分布式锁到底安全吗?

    网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现算法也看似合 ...

  6. 基于 Redis 的分布式锁到底安全吗(下)?

    自从我写完这个话题的上半部分之后,就感觉头脑中出现了许多细小的声音,久久挥之不去.它们就像是在为了一些鸡毛蒜皮的小事而相互争吵个不停.的确,有关分布式的话题就是这样,琐碎异常,而且每个人说的话听起来似 ...

  7. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  8. redis系列:基于redis的分布式锁

    一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...

  9. js 拉勾网效果_Node.js 中实践基于 Redis 的分布式锁实现

    在一些分布式环境下.多线程并发编程中,如果对同一资源进行读写操作,避免不了的一个就是资源竞争问题,通过引入分布式锁这一概念,可以解决数据一致性问题. 作者简介:五月君,Nodejs Developer ...

最新文章

  1. nodeJs --- web服务器创建
  2. 在Intelij IDEA中修改maven为国内镜像(阿里)
  3. burpsuite collaborato模块简介 dns log、http_https log、smtp_smtps log
  4. 模拟 CSU 1562 Fun House
  5. C#_List转换成DataTable
  6. WGS 1984 Web Mercator 对于在线地图服务的意义
  7. Elasticsearch-Jest 配置ES集群源码解读
  8. Qt--在.pro文件中添加链接库的写法
  9. 这次,甘肃的老百姓办理就医再也不用等了
  10. 前轮转向最大角度设计原来_转向不足是怎么回事?我们怎么去改变这种特性
  11. Head First 设计模式 —— 策略设计模式
  12. Python关键点常识
  13. 《基于Nginx的中间件架构》学习笔记---3.nginx的目录分析
  14. C++中引用变量的探究
  15. Latex参考文献引用格式,期刊参考文献引用格式注意事项
  16. 数据治理标准体系框架
  17. 完全查杀VIKING(威金蠕虫)病毒与免疫补丁
  18. java时间戳的单位_java – SimpleDateFormat – 解析时间戳,以毫秒为单位
  19. 复数与三角函数的转换
  20. c语言的字符数组strlen的详细使用

热门文章

  1. 获得显示器设置的分辨率
  2. Redis实现消息队列和订阅发布模式
  3. Docker常见问题总结
  4. SpringBoot配置Profile以及配置文件的加载位置
  5. centos 7 mysql 导入_linux centos7.3导出、导入、Mariadb(MySQL)数据库命令
  6. Go语言内部包--控制包成员的对外暴露
  7. sklearn中的逻辑回归
  8. @Configuration和@Bean注解详解
  9. 高可用集群的脑裂问题
  10. Dubbo基础知识总结