比如一个操作要修改的用户的状态,修改状态需要先读出用户的状态,在内存里进行修改,改完了再存回去。

如果这样的操作同时进行了,就会出现并发问题,因为读取和保存状态这两个操作不是原子的。

分布式锁:

分布式锁本质上要实现的目标就是在Redis里面占“坑”,当别的进程也要来占时,发现已经有人蹲在那里了,就

只好放弃或者稍后再试。

占坑一般是使用setnx(set if not exists)指令,只允许被一个客户端占坑。先来先到,用完了在调用del指令释放。

>setnx   lock:codehole   true
OK
...do  something  critical...
>del  lock:codehole
(integer) 1

但有个问题,如果逻辑执行到中间出现异常,可能会导致del指令没有被调用,这样就会陷入死锁,锁就得不到释放了。

这样我们可以拿到锁之后,再给锁加上一个过期时间,for example:5s

>setnx  lock:codehole  true
OK
>expire lock:codehole 5
...do something critical...
>del lock:codehole
(integer) 1

如果在setnx和expire之间服务器进程突然挂掉的,就会导致expire得不到执行,也会造成死锁。这个问题根源在于setnx和expire是两条指令而不是原子指令。如果这两条指令可以一起执行就不会出现问题。

>set lock:codehole true ex 5 nx
OK
...do something critical...
>del  lock:codehole

上面这个指令就是setnx和expire组合一起的原子指令,它就是分布式锁奥义的所在。

超时问题:

Redis的分布式锁解决超时问题,如果在加锁和释放锁之间的逻辑执行的太长,以至于超出了锁的超时限制,就会出现问题。因为

这时候第一个线程持有的锁过期了,临界区的逻辑还没有执行完,这个时候第二个线程就提前重新持有了这把锁,导致临界区代码不能得到严格的串行执行。

lua 脚本if  redis.call("get",keys[1] == argv[1] then  return redis.call("del",keys[1]))else return  0
end

可重入性:

可重入性是指线程在持有锁的情况下再次请求加锁,如果一个锁支持同一个线程的多次加锁,那么这个锁就是可重入的。

public class RedisWithReentrantLock{private  ThreadLocal<Map<String,Integer>> lockers=new  ThreadLocal<>();private  Jedis  jedis;public   RedisWithReentrantLock(Jedis jedis){this.jedis=jedis;}private  boolean  lock(String key){return jedis.set(key,"","nx","ex",5L)}private  void  unlock(){jedis.del(key);}private Map<String,Integer> currentLockers(){Map<String,Integer>  refs=lockers.get();if(refs!=null){return refs;}lockers.set(new HashMap<>());return  lockers.get();}public boolean lock(String key){Map<String,Integer>  refs=currentLockers();Integer refCnt=refs.get(key);if(refCnt!=null){refs.put(key,refCnt+1);return true;}boolean ok=this.lock(key);if(!ok){return false;}refs.put(key,1);return true;
}public boolean unlock(String key){Map<String,Integer>  refs=currentLockers();   Integer refCnt=refs.get(key);if(refCnt ==null){return false;}refCnt-=1;if(refCnt>0){refs.put(key,refCnt);}else{refs.remove(key);this.unlock(key);}return true;}
public static void main(String[] args){Jedis jedis=new Jedis();RedisWithReentrantLock  redis=new RedisWithReentrantLock(jedis);System.out.println(redis.lock("codehole"));System.out.println(redis.lock("codehole"));System.out.println(redis.unlock("codehole"));System.out.println(redis.unlock("codehole"));}
}

redis(千帆竞发--分布式锁)相关推荐

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

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

  2. Redis实现分布式锁的深入探究

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.分布式锁简介 锁 是一种用来解决多个执行线程 访问共享资源 错 ...

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

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

  4. Zookeeper和Redis实现分布式锁,附我的可靠性分析

    作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...

  5. Redis——由分布式锁造成的重大事故

    作者:浪漫先生 原文:juejin.im/post/6854573212831842311 前言 基于Redis使用分布式锁在当今已经不是什么新鲜事了.本篇文章主要是基于我们实际项目中因为redis分 ...

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

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

  7. 《Redis官方文档》用Redis构建分布式锁

    <Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...

  8. 《Redis官方文档》用Redis构建分布式锁(悲观锁)

    2019独角兽企业重金招聘Python工程师标准>>> **用Redis构建分布式锁 ** 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章 ...

  9. redis 实现分布式锁

    为什么80%的码农都做不了架构师?>>>    redis 实现分布式锁 伪代码 lock(){if(jedis.setNx("key",timestamp)){ ...

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

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

最新文章

  1. Kubernetes的共享GPU集群调度
  2. MFC显示位图 from http://blog.csdn.net/liuzhuomju/article/details/7299458
  3. MSC EASY5 2020中文版
  4. java中class.forname连接mysql数据库_数据库链接与 Class.forName()用法详解
  5. springboot加入com.fasterxml.jackson.core-jackson-databind依赖后报错Error creating bean with name ‘requestM
  6. 无法将成员变量添加到ID为 的控件中
  7. mock java_JAVA的mock工具mockito简介
  8. 教你如何监控 Java 线程池运行状态
  9. 报错 classes 拒绝访问_3种方式“移除”快速访问;为什么移除?你懂的...
  10. Excel字符串比较(exact)
  11. DBNull与Null的区别
  12. 快速排序——三种划分方式
  13. 古筝d调变降e调怎么办_问:古筝k是什么意思
  14. 【优化算法】多目标蝗虫优化算法(MOGOA)【含Matlab源码 937期】
  15. 让人感到惊艳的5款数据可视化大屏产品
  16. Oracle MOD函数的使用
  17. 展望未来「编程之路起始篇」
  18. DPU网络开发SDK——DPDK(十二)
  19. ebtables规则arpreply
  20. Ubuntu16使用小米WIFI做为AP

热门文章

  1. 应聘客户端主程需做哪些准备
  2. DELL笔记本E5400刷BIOS激活win7
  3. 微信上传临时素材|微信公众号发送图片
  4. 第九篇:人生中哪些是对错的选择?
  5. Ran 0 tests in 0.000s
  6. vue单文件组件中引用其他组件
  7. 手游传奇架设教程_传奇手游战神引擎架设教程
  8. 怎么用ping命令测试网速
  9. 2016民用安防2.0时代重新起航
  10. 长期在计算机房工作辐射大吗,在机房里工作辐射大吗