分布式锁

  分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。 举个不太恰当的例子:假设共享的资源就是一个房子,里面有各种书,分布式系统就是要进屋看书的人,分布式锁就是保证这个房子只有一个门并且一次只有一个人可以进,而且门只有一把钥匙。然后许多人要去看书,可以,排队,第一个人拿着钥匙把门打开进屋看书并且把门锁上,然后第二个人没有钥匙,那就等着,等第一个出来,然后你在拿着钥匙进去,然后就是以此类推

实现原理

  • 互斥性

    • 保证同一时间只有一个客户端可以拿到锁,也就是可以对共享资源进行操作

  • 安全性

    • 只有加锁的服务才能有解锁权限,也就是不能让a加的锁,bcd都可以解锁,如果都能解锁那分布式锁就没啥意义了

    • 可能出现的情况就是a去查询发现持有锁,就在准备解锁,这时候忽然a持有的锁过期了,然后b去获得锁,因为a锁过期,b拿到锁,这时候a继续执行第二步进行解锁如果不加校验,就将b持有的锁就给删除了

  • 避免死锁

    • 出现死锁就会导致后续的任何服务都拿不到锁,不能再对共享资源进行任何操作了

  • 保证加锁与解锁操作是原子性操作

    • 这个其实属于是实现分布式锁的问题,假设a用redis实现分布式锁
    • 假设加锁操作,操作步骤分为两步:

    • 1,设置key set(key,value)2,给key设置过期时间

    • 假设现在a刚实现set后,程序崩了就导致了没给key设置过期时间就导致key一直存在就发生了死锁

如何实现分布式锁

  实现分布式锁的方式有很多,只要满足上述条件的都可以实现分布式锁,比如数据库,redis,zookeeper,在这里就先讲一下如何使用redis实现分布式锁

使用redis实现分布式锁

  • 使用redis命令 set key value NX EX max-lock-time 实现加锁

  • 使用redis命令 EVAL 实现解锁

加锁:

  Jedis jedis = new Jedis("127.0.0.1", 6379);private static final String SUCCESS = "OK";/*** 加锁操作* @param key 锁标识* @param value 客户端标识* @param timeOut 过期时间*/public Boolean lock(String key,String value,Long timeOut){String var1 = jedis.set(key,value,"NX","EX",timeOut);if(LOCK_SUCCESS.equals(var1)){return true;}return false;}

解读:

  • 加锁操作:jedis.set(key,value,"NX","EX",timeOut)【保证加锁的原子操作】

  • key就是redis的key值作为锁的标识,value在这里作为客户端的标识,只有key-value都比配才有删除锁的权利【保证安全性】

  • 通过timeOut设置过期时间保证不会出现死锁【避免死锁】

  • NX,EX什么意思?

    • NX:只有这个key不存才的时候才会进行操作,if not exists;

    • EX:设置key的过期时间为秒,具体时间由第5个参数决定


解锁

  Jedis jedis = new Jedis("127.0.0.1", 6379);private static final Long UNLOCK_SUCCESS = 1L;/*** 解锁操作* @param key 锁标识* @param value 客户端标识* @return*/public static Boolean unLock(String key,String value){String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else  return 0 end";Object var2 = jedis.eval(luaScript,Collections.singletonList(key), Collections.singletonList(value));if (UNLOCK_SUCCESS == var2) {return true;}return false;}

解读:

  • luaScript 这个字符串是个lua脚本,代表的意思是如果根据key拿到的value跟传入的value相同就执行del,否则就返回0【保证安全性】

  • jedis.eval(String,list,list);这个命令就是去执行lua脚本,KEYS的集合就是第二个参数,ARGV的集合就是第三参数【保证解锁的原子操作】

上述就实现了怎么使用redis去正确的实现分布式锁,但是有个小缺陷就是锁过期时间要设置为多少合适,这个其实还是需要去根据业务场景考量一下的


  上面那只是讲了加锁与解锁的操作,试想一下如果在业务中去拿锁如果没有拿到是应该阻塞着一直等待还是直接返回,这个问题其实可以写一个重试机制,根据重试次数和重试时间做一个循环去拿锁,当然这个重试的次数和时间设多少合适,是需要根据自身业务去衡量的

    /*** 重试机制* @param key 锁标识* @param value 客户端标识* @param timeOut 过期时间* @param retry 重试次数* @param sleepTime 重试间隔时间* @return*/public Boolean lockRetry(String key,String value,Long timeOut,Integer retry,Long sleepTime){Boolean flag = false;try {for (int i=0;i<retry;i++){flag = lock(key,value,timeOut);if(flag){break;}Thread.sleep(sleepTime);}}catch (Exception e){e.printStackTrace();}return flag;}

  

到这,用redis实现分布式锁就写完了,下次用zookeeper去实现分布式锁,欢迎留言吐槽 txtx

文中set命令详解:http://redisdoc.com/string/set.html

扫码关注我滴公众号啊

转载于:https://www.cnblogs.com/cmyxn/p/9047848.html

什么是分布式锁及正确使用redis实现分布式锁相关推荐

  1. mysql锁描述正确的是_MySQL表锁详解

    锁是计算机协调多个进程或纯线程并发访问某一资源的机制.而表锁由MySQL Server 实现,一般在执行DDL语句时会对整个表进行加锁,比如说ALTER TABLE等操作.在执行SQL语句时,也可以明 ...

  2. java分布式调度框架_基于Redis的分布式Java任务执行和调度框架

    Redisson是使用Redis实现分布式任务执行和调度的Java开源项目,它是通过标准JDK的ExecutorService和ScheduledExecutorService API实现的,被提交的 ...

  3. **Java有哪些悲观锁的实现_80% 人不知道的 Redis 分布式锁的正确实现方式(Java 版)...

    点击上方"小哈学Java",选择"星标" 回复"资源",领取全网最火的Java核心知识总结 来源:http://sina.lt/gfZU 前 ...

  4. Redis分布式锁【正确实现方式】

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  5. Redis分布式锁的正确实现方式(Java版)

    转自:https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/ 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于 ...

  6. Redis分布式锁的正确实现方式

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  7. Redis分布式锁的正确实现方式(转发来至博客园Ruthless )

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

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

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

  9. 基于Redis的分布式锁实现

    本文转自 一.分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问,Java中我们一般可以使用synchronized语法和ReetrantLock去保证,这实际上是本地锁的 ...

最新文章

  1. 极小连通子图和极大连通子图_强连通分量与拓扑排序
  2. docker process tree
  3. cmd命令安装composer踩坑
  4. 年龄测试计算器软件,抖音很火的年龄计算器
  5. MPP 二、Greenplum数据加载
  6. sudo 安装 常见错误
  7. 使用GUI工具Portainer.io管控Docker容器
  8. 140种Python标准库、第三方库和外部工具都有了
  9. python创建变量revenue、并赋值为98765_第七章:Python之数据库编程
  10. h.264 视频解码的一点小经验
  11. Mysql 引优化分析
  12. html3d龙卷风特效代码,使用Canvas 2D模拟出来的3D龙卷风动画特效
  13. App Store审核规范
  14. element cannot be mapped to a null key
  15. 如何更改xp计算机用户名和密码错误,XP更改开机密码提示“Windows不能更改密码”如何解决...
  16. 利用Volatility进行Windows内存取证分析(二):内核对象、内核池学习小记
  17. pat 训练题 7-5 基友团 (25分) 暴力判团和最大团
  18. 短信验证码平台哪家速度快又稳定,推荐下?
  19. 未明学院数据分析报告:金融专业如何找实习?数据分析告诉你整个金融实习市场全貌!
  20. python 小于号和大于号同时使用

热门文章

  1. 《C++游戏编程入门(第4版)》——1.11 问题讨论
  2. 华为呼叫中心解决方案学习笔记一(方案概述)
  3. MapReduce V1:Job提交流程之JobTracker端分析
  4. Java——递归调用
  5. 【小议】centos与ubuntu的区别
  6. MyBatis mapper 注解过程中通过 LanguageDriver 实现动态 SQL
  7. IO(File 递归)
  8. AWVS/Nessus/Burpsuite的简单使用
  9. TCP/IP协议各层首部汇总
  10. mac下使用n管理node版本