博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redis--分布式锁实现
阅读量:2352 次
发布时间:2019-05-10

本文共 4777 字,大约阅读时间需要 15 分钟。

获取锁:

@Override	public String acquireLockWithTimeout(Jedis jedis,String lockName, long acquireTimeout, long lockTimeout) {
//Jedis jedis =getJedis(); try {
String identifier = UUID.randomUUID().toString(); String lockKey = "lock:" + lockName; int lockExpire = (int) (lockTimeout / 1000); long endTime = System.currentTimeMillis() + acquireTimeout; while (System.currentTimeMillis() < endTime) {
logger.info("acquireLockWithTimeout->jedis->"+jedis); // 尝试设置key-value值,并且key不存在 if (jedis.setnx(lockKey, identifier) == 1) {
// key不存在,并且设置成功,获取锁成功 jedis.expire(lockKey, lockExpire); return identifier; } //处理其他占用锁并且无法释放锁的情况 if (jedis.ttl(lockKey) == -1) {
// key 存在但没有设置剩余生存时间 jedis.expire(lockKey, lockExpire); } try {
Thread.sleep(1); } catch (InterruptedException ie) {
Thread.currentThread().interrupt(); } } }catch(Exception e) {
e.printStackTrace(); }finally {
/*if(jedis!=null) { jedis.close(); }*/ } return null; }

流程图

在这里插入图片描述
R e d i s 做 分 布 式 锁 时 需 要 注 意 获 取 锁 时 , 如 果 获 取 成 功 , 设 置 过 期 时 间 , \color{#FF0000}{Redis做分布式锁时需要注意获取锁时,如果获取成功,设置过期时间,} Redis
获 取 失 败 , 要 判 断 是 否 是 否 设 置 了 过 期 时 间 , 没 有 的 话 , 要 设 置 过 期 时 间 , 防 止 获 取 成 功 了 , \color{#FF0000}{获取失败,要判断是否是否设置了过期时间,没有的话,要设置过期时间,防止获取成功了,}
但 是 设 置 过 期 时 间 的 时 候 r e d i s 炸 了 。 \color{#FF0000}{但是设置过期时间的时候redis炸了。} redis

释放锁:

@Override	public boolean releaseLock(Jedis jedis,String lockName, String identifier) {
//Jedis jedis = getJedis(); try {
String lockKey = "lock:" + lockName; while (true) {
// 监控key jedis.watch(lockKey); if (identifier.equals(jedis.get(lockKey))) {
Transaction trans = jedis.multi(); trans.del(lockKey); List results = trans.exec(); if (results == null) {
continue; } return true; } jedis.unwatch(); break; } }catch(Exception e) {
e.printStackTrace(); }finally {
/*if(jedis!=null) { jedis.close(); }*/ } return false; }

删 除 的 时 候 需 要 注 意 先 监 控 k e y , 然 后 比 较 v a l u e , 再 删 除 , 之 所 以 需 要 监 控 , 是 因 为 再 比 较 后 可 能 值 会 出 现 变 化 \color{#FF0000}{删除的时候需要注意先监控key,然后比较value,再删除,之所以需要监控,是因为再比较后可能值会出现变化} keyvalue

那 样 就 会 出 现 把 别 人 刚 刚 获 取 到 的 值 给 删 除 了 \color{#FF0000}{那样就会出现把别人刚刚获取到的值给删除了}

测试:

@RunWith(SpringRunner.class)@SpringBootTestpublic class LockServiceTest {
private static final Logger logger = LoggerFactory.getLogger(LockServiceTest.class); @Autowired private RedisService redisService; @Autowired private RedisTemplate
redisTemplate; private AtomicInteger atomicI = new AtomicInteger(0); @Test public void testJedis() {
/*ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10); // for (int i = 0; i < 10; i++) { // 定时执行任务,每隔10秒钟执行一次 executorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { Jedis jedis = redisService.getJedis(); String value = jedis.get("aaa"); logger.info("=================【{}】=================", value); } }, 0, 10, TimeUnit.SECONDS); // }*/ }
@Test	public void testLock() {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) {
// 定时执行任务,每隔500毫秒执行一次 fixedThreadPool.execute(new Runnable() {
@Override public void run() {
Jedis jedis=null; atomicI.incrementAndGet(); String lockName = "lock01"; String id = ""; try {
long acquireTimeout = 10000; long lockTimeout = 10000; long startTime = System.currentTimeMillis(); id = redisService.acquireLockWithTimeout(jedis,lockName, acquireTimeout, lockTimeout); long endTime = System.currentTimeMillis(); if (id != null) {
logger.info("获取锁成功,id:【{}】花费时间:【{}】" ,id,(endTime - startTime)); } else {
logger.info("获取锁失败,花费时间:【{}】",(endTime - startTime)); } Thread.sleep(1000); } catch (Exception e) {
e.printStackTrace(); } finally {
if (id != "" && id != null) {
logger.info("开始释放锁id:【{}】",id); redisService.releaseLock(jedis,lockName, id); } else {
logger.info("无锁需要释放"); } } } }); } while(true) {
if(fixedThreadPool.isTerminated()) {
System.out.println("run over"); System.out.println("i="+atomicI); break; } } }}

如上的实现方式在主备、哨兵模式下会存在问题,比如在主节点执行了set后,然后宕机了,从节点同步获取到锁信息,那么其他客户端也会再次获取到锁。然后就出现了红锁。

官网中提到的红锁,大概流程为:向所有的节点发送获取锁的逻辑,如果有超过一半+1的实例返回ok,并且在时间节点内,那么就算获取锁成功,释放锁时也是一样,向所有的实例发送删除的命令。

redission分布式锁的实现

在这里插入图片描述

参考:http://www.redis.cn/topics/distlock.html

摘自《Redis实战》。

参考:http://www.redis.cn/topics/distlock.html

转载地址:http://juhvb.baihongyu.com/

你可能感兴趣的文章
SourceInsight添加对汇编语言文件.s和.S的支持
查看>>
windows 下实现函数打桩:拦截API方式
查看>>
获取Windows系统版本
查看>>
漫谈兼容内核之十二:Windows的APC机制
查看>>
21.windbg-.lastevent、!analyze(dump分析、异常错误码查询)
查看>>
16.windbg-.frame、dt(切换局部上下文、查找结构体)
查看>>
开源任务管理器 Process Hacker (Windows)
查看>>
快速发现Windows中毒的工具:Process Hacker
查看>>
Process Hacker源码中的用户态hook的做法
查看>>
Get IT技能知识库 50个领域一键直达
查看>>
浅析C++中的this指针及汇编实现
查看>>
关于32位程序在64位系统下运行中需要注意的重定向问题(有图有真相)(***)
查看>>
解决win10系统中截图异常放大的问题
查看>>
关于Windows高DPI的一些简单总结
查看>>
tlb文件为何而生?
查看>>
IE9 GPU硬件加速到底是实用创新还是噱头
查看>>
几种TCP连接中出现RST的情况
查看>>
IAAS、SAAS 和 PAAS 的区别、理解
查看>>
RichEdit对ole 对象的相关支持总结
查看>>
(分享)win10下双显示屏独立设置不同缩放率的方法
查看>>