在开始提到Redis分布式锁之前,先说一下redis中的两个命令。

SETNX key value

setnx 是SET if Not eXists(如果不存在,则 SET)的简写。

用法如图,如果不存在set成功返回int的1,这个key存在了返回0。

SETEX key seconds value

上面这个命令的含义是:

将值 value关 联到 key,并将 key的生存时间设为 seconds (以秒为单位)。

如果key已经存在,setex命令将覆写旧值。

其中setex是一个原子性(atomic)操作,关联值和设置生存时间两个动作会在同一时间内完成。

这两个命令是实现redis分布式锁的关键,同时reddission底层也是通过这两个命令结合lua脚本完成redis分布式锁的

回到主题:

实现Redis的分布式锁,除了自己基于redis client原生api来实现之外,还可以使用开源框架:Redission

Redisson是一个企业级的开源Redis Client,也提供了分布式锁的支持,如果自己写代码来通过redis设置一个值,是通过下面这个命令设置的。

SET anyLock unique_value NX PX 30000

具体含义见下图:

这里设置的超时时间是30s,假如我超过30s都还没有完成业务逻辑的情况下,key会过期,其他线程有可能会获取到锁。

这样一来的话,第一个线程还没执行完业务逻辑,第二个线程进来了也会出现线程安全问题。所以我们还需要额外的去维护这个过期时间,太麻烦了~

而使用redission,只需要通过他的api中的lock和unlock即可完成分布式锁,他帮我们考虑了很多细节:

  • redisson所有指令都通过lua脚本执行,redis支持lua脚本原子性执行
  • redisson设置一个key的默认过期时间为30s,如果某个客户端持有一个锁超过了30s怎么办?
    redisson中有一个watchdog看门狗的概念,翻译过来就是看门狗,它会在你获取锁之后,每隔10秒帮你把key的超时时间设为30s

这样的话,就算一直持有锁也不会出现key过期了,其他线程获取到锁的问题了。

  • redisson的"看门狗"逻辑保证了没有死锁发生。
    注意:如果机器宕机了,看门狗也就没了。此时就不会延长key的过期时间,到了30s之后就会自动过期了,其他线程可以获取到锁)


比起自己手写代码会帮助开发者少关注贼多细节

同时redission支持多种连接模式

//单机
RedissonClient redisson = Redisson.create();
Config config = new Config();
config.useSingleServer().setAddress("myredisserver:6379");
RedissonClient redisson = Redisson.create(config);//主从
Config config = new Config();
config.useMasterSlaveServers().setMasterAddress("127.0.0.1:6379").addSlaveAddress("127.0.0.1:6389", "127.0.0.1:6332", "127.0.0.1:6419").addSlaveAddress("127.0.0.1:6399");
RedissonClient redisson = Redisson.create(config);//哨兵
Config config = new Config();
config.useSentinelServers().setMasterName("mymaster").addSentinelAddress("127.0.0.1:26389", "127.0.0.1:26379").addSentinelAddress("127.0.0.1:26319");
RedissonClient redisson = Redisson.create(config);//集群
Config config = new Config();
config.useClusterServers().setScanInterval(2000) // cluster state scan interval in milliseconds.addNodeAddress("127.0.0.1:7000", "127.0.0.1:7001").addNodeAddress("127.0.0.1:7002");
RedissonClient redisson = Redisson.create(config);

下面直接贴代码,这里使用的是单机模式,切换自己改一下连接模式就行:
1.导入依赖:

<!-- org.redisson/redisson 分布式专用--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.5.3</version></dependency>

2.编写配置类:

@SpringBootApplication
public class RedisLockApplication {public static void main(String[] args) {SpringApplication.run(RedisLockApplication.class, args);}@Beanpublic Redisson redisson(){// 单机模式Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(0);return (Redisson) Redisson.create(config);}
}

3.上锁

@RestController
public class IndexController {@Resourceprivate Redisson redisson;@Resourceprivate StringRedisTemplate stringRedisTemplate; // 居然根据名字来找的,不是根据类型。。。/*** 代码有什么问题?*      1.线程安全问题,多个线程同时访问就可能出现错误,用synchronized可以解决但是性能不好*          synchronized在高并发情况下还是有bug出现,会出现超卖,可以用jmeter压测*      2.设置redis锁解决分布式场景之后,超时时间设置10s合理吗?适合场景问题?如果10s中之内没有处理完,处理到一半呢?*          15s--10s后释放锁--还需要5s,5s后释放了其他人的锁*          8s--5s后我的锁被人释放了,其他线程又来了*          循环下去,锁的是别人....这不就完全乱套了,这锁完全没用啊*        解决方法:你不是可能存在释放别人的锁的情况吗?那就设置识别号,识别到只能是自己的才能被释放*        这只是解决了释放别人的锁的问题,你自己没有执行完就已经超时的问题呢?*        答案:开启子线程定时器来延长超时时间咯,子线程每隔一段时间就去查看是否完成,没完成就加时,那这个一段时间要多长呢?*             三分之一过期时间,其他人的实践经验。*        所以:我们现在又要造轮子了吗?是否有其他人已经考虑过这个问题并做开源了呢?*        那肯定有啊,不然我写这个干吗。redisson,比jedis强大,专对分布式**      3.redisson*          大概阐述一下这个锁的操作:*          当一个redisson线程过来获取到锁时,后台会有其他线程去检查是否还持有锁,*          还持有说明还没执行结束,就会继续延长锁的时间,大概10s去轮询。(三分之一)*          另外一个线程过来,如果没有获取锁成功,就会while自旋尝试加锁。*          clientId他在底层实现了。**          3.1如果使用的是Redis主从架构呢,主节点宕了,从节点怎么处理?但这是锁还没有被同步过去,其他线程就过来访问了呢?*          3.2另外如何提升性能呢?*              - 商品库存分段存储,key不一样,每个段的数量越小性能不就越高嘛,而且锁定不同的key值** @return*/@RequestMapping("/deduct_stock")public String deductStock() {// 0.标识号String clientID = UUID.randomUUID().toString();// 1.这个相当于一把锁,控制只能一个人来String lockKey = "product001";RLock lock = redisson.getLock(lockKey); // 3.1try{/*// 2.获取锁Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "yjiewei");// jedis.setnx(key, value);// 3.如果突发宕机,锁没有释放掉怎么办,key过期处理(10s),但是如果在获取锁之后就出问题呢,这一步也没有成功,大招:二合一stringRedisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);
*/// 2-3
/*          Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientID, 10, TimeUnit.SECONDS);if (!result){return "error";}
*/// 3.1 解决过期时间内还未完成操作的问题lock.lock(30, TimeUnit.SECONDS); // 先拿锁,再设置超时时间// 4.真正操作商品库存synchronized (this){int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock");if (stock > 0){int realStock = stock - 1;stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key, value);System.out.println("扣减成功,剩余库存:" + realStock);}else {System.out.println("扣减失败,库存不足!");}}}finally {lock.unlock(); // 释放锁
/*if (clientID.equals(stringRedisTemplate.opsForValue().get(lockKey))) {// 5.释放锁,放在finally块中防止没有释放锁导致死锁问题stringRedisTemplate.delete(lockKey);}
*/}return "end";}
}

redission实现分布式锁相关推荐

  1. redission java_Java注解如何基于Redission实现分布式锁

    这篇文章主要介绍了Java注解如何基于Redission实现分布式锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.定义注解类 @Target( ...

  2. Redission实现分布式锁完美方案 以及 Lua 脚本浅谈

    Redission实现分布式锁完美方案 以及 Lua 脚本浅谈 文章目录 Redission实现分布式锁完美方案 以及 Lua 脚本浅谈 前言 常见分布式锁方案对比 分布式锁需满足四个条件 Redis ...

  3. 基于Redission实现分布式锁

    实现Redis的分布式锁,除了自己基于redis client原生api来实现之外,还可以使用开源框架:Redission Redisson是一个企业级的开源Redis Client,也提供了分布式锁 ...

  4. Redis分布式锁-这一篇全了解(Redission实现分布式锁完美方案)

    前言 在某些场景中,多个进程必须以互斥的方式独占共享资源,这时用分布式锁是最直接有效的. 随着技术快速发展,数据规模增大,分布式系统越来越普及,一个应用往往会部署在多台机器上(多节点),在有些场景中, ...

  5. redis和redission分布式锁原理及区别

    redis和redission分布式锁原理及区别 我最近做租车项目,在处理分布式时用到分布式锁,我发现很多同事都在网上找分布式锁的资料,但是看的资料都不是很全,所以在这里我谈谈自己的分布式锁理解. 结 ...

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

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

  7. 分布式锁实现:Redis

    前言 单机环境下我们可以通过JAVA的Synchronized和Lock来实现进程内部的锁,但是随着分布式应用和集群环境的出现,系统资源的竞争从单进程多线程的竞争变成了多进程的竞争,这时候就需要分布式 ...

  8. Redis进阶- Redisson分布式锁实现原理及源码解析

    文章目录 Pre 用法 Redisson分布式锁实现原理 Redisson分布式锁源码分析 redisson.getLock(lockKey) 的逻辑 redissonLock.lock()的逻辑 r ...

  9. 如何用redis实现分布式锁?这篇文章教你用redisson实现分布式锁,封装之后的方法更好用!

    使用redission实现分布式锁 添加配置类 import org.redisson.Redisson; import org.springframework.beans.factory.annot ...

  10. 基于redis实现分布式锁思考

    分布式锁 基于redis实现分布式锁思考几个问题??? synchronized锁为什么不能应用于分布式锁? synchronized虽然能够解决同步问题,但是每次只有一个线程访问,并且synchro ...

最新文章

  1. 数据蒋堂 | BI系统的前置计算
  2. WIN32开发:如何获取父进程的ID
  3. C#中DictionaryTKey,TValue排序方式
  4. .net 把一个对象赋值给一个参数_Java:new一个对象的过程中发生了什么?
  5. python+selenium配置Edge浏览器
  6. .NET Core跨平台的奥秘[上篇]:历史的枷锁
  7. mysql用户如何迁移_迁移MySQL用户及权限
  8. 根号x_8.八年级数学:根号(2a1)=12a,怎么求a的取值范围?二次根式
  9. mybatis 复习笔记03
  10. 局域网的主机如何连接外网
  11. 云计算与大数据技术应用
  12. Qt + OpenGL 教程(三):线
  13. 基于STM32的AT24C08数据读写
  14. PDF文件不能打印的五种解决方案
  15. 跨域组播--MBGP+MSDP+Anycast RP
  16. python爬虫笔记(1)
  17. Android开发之通过浏览器链接打开任意app页面
  18. adb shell 模拟器 关闭\打开WIFI
  19. 根据视频地址获取视频的第一帧画面做为封面 IllegalArgumentException
  20. 天南地北双飞客,老翅几回寒暑!

热门文章

  1. 《银河英雄传说》杨威利经典语录2
  2. 听说QQ扫码登录很难,办了它
  3. OpenHarmony开源鸿蒙学习入门-应用开发之使用eTS语法示例项目讲解
  4. java实践课程感想_Java课程总结与感想
  5. linux下xz格式,linux下 x.tar.xz格式文件的解压方法
  6. 前端每日实战:50# 视频演示如何用纯 CSS 创作一个永动的牛顿摆
  7. 基于虚拟机的VxWorks实验平台设计与实现(读研时的一篇论文)
  8. 【lzy学习笔记-dive into deep learning】数学预备 2.1-2.4
  9. hive学习第五章:查询
  10. 大数据分析与应用技术创新平台