展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Redis分布式锁怎么实现及应用场景是什么

Redis分布式锁怎么实现及应用场景是什么

Redis Assistant
Redis Assistant

Redis Assistant 是一款为Redis设计的高效可视化管理与监控工具,提供多种操作模式,高效处理服务器数据。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

¥19
Windows/macOS/Linux 2026-08-22
正版软件 Windows macOS软件 Linux 数据库管理工具
立即下载

引言锁是开发过程中十分常见的工具,你一定不陌生,悲观锁,乐观锁,排它锁,公平锁,非公平锁等等,很多概念,如果你对java里的锁还不了解,可以参考这一篇:不可不说的Java“锁”事,这一篇写的很全面了,但是对于初学者,知道这些锁的概念,由于缺乏实际工作经验,可能并不了解锁的实际使用场景,Java中可以通过Volatile、Synchronized、ReentrantLock三个关键字来实现线程的安全,这部分知识在第一轮基础面试里一定会问(要熟练掌握哦)。在分布式系统中Java这些锁技术是无法同时锁住两台机器

本文目录

      引言

      锁是开发过程中十分常见的工具,你一定不陌生,悲观锁,乐观锁,排它锁,公平锁,非公平锁等等,很多概念,如果你对java里的锁还不了解,可以参考这一篇:不可不说的Java“锁”事,这一篇写的很全面了,但是对于初学者,知道这些锁的概念,由于缺乏实际工作经验,可能并不了解锁的实际使用场景,Java中可以通过Volatile、Synchronized、ReentrantLock 三个关键字来实现线程的安全,这部分知识在第一轮基础面试里一定会问(要熟练掌握哦)。

      在分布式系统中Java这些锁技术是无法同时锁住两台机器上的代码,所以要通过分布式锁来实现,熟练使用分布式锁也是大厂开发必会的技能。

      1、面试官:

      你有遇到需要使用分布式锁的场景吗?

      问题分析:这个问题主要作为引子,先要了解什么场景下需要使用分布式锁,分布式锁要解决什么问题,在此前提下有助于你更好的理解分布式锁的实现原理。

      使用分布式锁的场景一般需要满足以下场景:

      • 系统是一个分布式系统,java的锁已经锁不住了。

      • 操作共享资源,比如库里唯一的用户数据。

      • 同步访问,即多个进程同时操作共享资源。

      答:说一个我在项目中使用分布式锁场景的例子:

      消费积分在很多系统里都有,信用卡,电商网站,通过积分换礼品等,这里“消费积分”这个操作是需要使用锁的典型场景。

      事件A:

       以积分兑换礼品为例来讲,完整的积分消费过程简单分成3步:

      A1:用户选中商品,发起兑换提交订单。

      A2:系统读取用户剩余积分:判断用户当前积分是否充足。

      A3:扣掉用户积分。

      事件B: 

      系统给用户发放积分也简单分成3步:

      B1:计算用户当天应得积分

      B2:读取用户原有积分

      B3:在原有积分上增加本次应得积分

      那么问题来了,如果用户消费积分和用户累加积分同时发生(同时用户积分进行操作)会怎样?

      假设:用户在消费积分的同时恰好离线任务在计算积分给用户发放积分(如根据用户当天的消费额),这两件事同时进行,下面的逻辑有点绕,耐心理解。

      用户U有1000积分(记录用户积分的数据可以理解为共享资源),本次兑换要消耗掉999积分。

      不加锁的情况:事件A程序在执行到第2步读积分时,A:2操作读到的结果是1000分,判断剩余积分够本次兑换,紧接着要执行第3步A:3操作扣积分(1000 - 999 = 1),正常结果应该是用户还是1分。但是这个时候事件B也在执行,本次要给用户U发放100积分,两个线程同时进行(同步访问),不加锁的情况,就会有下面这种可能,A:2 -> B:2 -> A:3 -> B:3 ,在A:3尚未完成前(扣积分,1000 - 999),用户U总积分被事件B的线程读取了,最后用户U的总积分变成了1100分,还白白兑换了一个999积分的礼物,这显然不符合预期结果。

      有人说怎么可能这么巧同时操作用户积分,cpu那么快,只要用户足够多,并发量足够大,墨菲定律迟早生效,出现上述bug只是时间问题,还有可能被黑产行业卡住这个bug疯狂薅羊毛,这个时候作为开发人员要解决这个隐患就必须了解锁的使用。

      (写代码是一项严谨的事儿!)

      Java本身提供了两种内置的锁的实现,一种是由JVM实现的synchronized 和 JDK 提供的 Lock,以及很多原子操作类都是线程安全的,当你的应用是单机或者说单进程应用时,可以使用这两种锁来实现锁。

      但是当下互联网公司的系统几乎都是分布式的,这个时候Java自带的 synchronized 或 Lock 已经无法满足分布式环境下锁的要求了,因为代码会部署在多台机器上,为了解决这个问题,分布式锁应运而生,分布式锁的特点是多进程,多个物理机器上无法共享内存,常见的解决办法是基于内存层的干涉,落地方案就是基于Redis的分布式锁 or ZooKeeper分布式锁。

      (我分析的不能更详细了,面试官再不满意?)

      2、面试官:

      Redis分布式锁实现方法

      问题分析:目前分布式锁的实现方式主要有两种,1.基于Redis Cluster模式。2.基于Zookeeper 集群模式。

      优先掌握这两种,应付面试基本没问题了。

      答:

      1、基于Redis的分布式锁

      方法一:使用setnx命令加锁

      public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) {
      		// 第一步:加锁
          Long result = jedis.setnx(lockKey, requestId);
          if (result == 1) {
              // 第二步:设置过期时间
              jedis.expire(lockKey, expireTime);
          }
      }

      代码解释:

      setnx命令,意思就是 set if not exist,如果lockKey不存在,把key存入Redis,保存成功后如果result返回1,表示设置成功,如果非1,表示失败,别的线程已经设置过了。

      expire(),设置过期时间,防止死锁,假设,如果一个锁set后,一直不删掉,那这个锁相当于一直存在,产生死锁。

      (讲到这里,我还要和面试官强调一个“但是”)

      思考,我上面的方法哪里与缺陷?继续给面试官解释…

      加锁总共分两步,第一步jedis.setnx,第二步jedis.expire设置过期时间,setnx与expire不是一个原子操作,如果程序执行完第一步后异常了,第二步jedis.expire(lockKey, expireTime)没有得到执行,相当于这个锁没有过期时间,有产生死锁的可能。正对这个问题如何改进?

      改进:

      public class RedisLockDemo {
          private static final String SET_IF_NOT_EXIST = "NX";
          private static final String SET_WITH_EXPIRE_TIME = "PX";
          /**
           * 获取分布式锁
           * @param jedis Redis客户端
           * @param lockKey 锁
           * @param requestId 请求标识
           * @param expireTime 超期时间
           * @return 是否获取成功
           */
          public static boolean getLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
      				// 两步合二为一,一行代码加锁并设置 + 过期时间。
              if (1 == jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)) {
                  return true;//加锁成功
              }
              return false;//加锁失败
          }
      }

      代码解释:

      将加锁和设置过期时间合二为一,一行代码搞定,原子操作。

      (没等面试官开口追问,面试官很满意了)

      3、面试官: 那解锁操作呢?

      答:

      释放锁就是删除key

      使用del命令解锁

      public static void unLock(Jedis jedis, String lockKey, String requestId) {
          // 第一步: 使用 requestId 判断加锁与解锁是不是同一个客户端
          if (requestId.equals(jedis.get(lockKey))) {
              // 第二步: 若在此时,这把锁突然不是这个客户端的,则会误解锁
              jedis.del(lockKey);
          }
      }

      代码解释: 通过 requestId 判断加锁与解锁是不是同一个客户端和 jedis.del(lockKey) 两步不是原子操作,理论上会出现在执行完第一步if判断操作后锁其实已经过期,并且被其它线程获取,这是时候在执行jedis.del(lockKey)操作,相当于把别人的锁释放了,这是不合理的。当然,这是非常极端的情况,如果unLock方法里第一步和第二步没有其它业务操作,把上面的代码扔到线上,可能也不会真的出现问题,原因第一是业务并发量不高,根本不会暴露这个缺陷,那么问题还不大。

      但是写代码是严谨的工作,能完美则必须完美。针对上述代码中的问题,提出改进。

      代码改进:

      public class RedisTool {
          private static final Long RELEASE_SUCCESS = 1L;
          /**
           * 释放分布式锁
           * @param jedis Redis客户端
           * @param lockKey 锁
           * @param requestId 请求标识
           * @return 是否释放成功
           */
          public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
              String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
              Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
              if (RELEASE_SUCCESS.equals(result)) {
                  return true;
              }
              return false;
          }
      }

      代码解释:

      通过 jedis 客户端的 eval 方法和 script 脚本一行代码搞定,解决方法一中的原子问题。

      3、面试官:

      基于 ZooKeeper 的分布式锁实现原理

      答:还是积分消费与积分累加的例子:事件A和事件B同时需要进行对积分的修改操作,两台机器同时进行,正确的业务逻辑上让一台机器先执行完后另外一个机器再执行,要么事件A先执行,要么事件B先执行,这样才能保证不会出现A:2 -> B:2 -> A:3 -> B:3这种积分越花越多的情况(想到这种bug一旦上线,老板要生气了,我可能要哭了)。

      怎么办?使用 zookeeper 分布式锁。

      一个机器接收到了请求之后,先获取 zookeeper 上的一把分布式锁(zk会创建一个 znode),执行操作;然后另外一个机器也尝试去创建那个 znode,结果发现自己创建不了,因为被别人创建了,那只能等待,等第一个机器执行完了方可拿到锁。

      使用 ZooKeeper 的顺序节点特性,假如我们在/lock/目录下创建3个节点,ZK集群会按照发起创建的顺序来创建节点,节点分为/lock/0000000001、/lock/0000000002、/lock/0000000003,最后一位数是依次递增的,节点名由zk来完成。

      ZK中还有一种名为临时节点的节点,临时节点由某个客户端创建,当客户端与ZK集群断开连接,则该节点自动被删除。EPHEMERAL_SEQUENTIAL为临时顺序节点。

      根据ZK中节点是否存在,可以作为分布式锁的锁状态,以此来实现一个分布式锁,下面是分布式锁的基本逻辑:

      • 客户端调用create()方法创建名为“/dlm-locks/lockname/lock-”的临时顺序节点。

      • 客户端调用getChildren(“lockname”)方法来获取所有已经创建的子节点。

      • 客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点是所有节点中序号最小的,就是看自己创建的序列号是否排第一,如果是第一,那么就认为这个客户端获得了锁,在它前面没有别的客户端拿到锁。

      • 如果创建的节点不是所有节点中需要最小的,那么则监视比自己创建节点的序列号小的最大的节点,进入等待。直到下次监视的子节点变更的时候,再进行子节点的获取,判断是否获取锁。

      释放锁的过程相对比较简单,就是删除自己创建的那个子节点即可,不过也仍需要考虑删除节点失败等异常情况。

      额外补充

      分布式锁还可以从数据库下手解决问题

      方法一:

      利用 Mysql 的锁表,创建一张表,设置一个 UNIQUE KEY 这个 KEY 就是要锁的 KEY,所以同一个 KEY 在mysql表里只能插入一次了,这样对锁的竞争就交给了数据库,处理同一个 KEY 数据库保证了只有一个节点能插入成功,其他节点都会插入失败。

      这样 lock 和 unlock 的思路就很简单了,伪代码:

      def lock :
          exec sql: insert into locked—table (xxx) values (xxx)
          if result == true :
              return true
          else :
              return false
      def unlock :
          exec sql: delete from lockedOrder where order_id='order_id'

      方法二:

      使用流水号+时间戳做幂等操作,可以看作是一个不会释放的锁。

      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发
      相关文章 更多
      精品专题 更多
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      macOS软件

      正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

      IOS软件

      正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

      AI

      正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

      Mac软件 更多
      Aperty macOS版
      Aperty macOS版

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      火山引擎 网页版
      火山引擎 网页版

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      立刻MV 网页版
      立刻MV 网页版

      立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

      蛙蛙写作 网页版
      蛙蛙写作 网页版

      蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

      讯飞智作 网页版
      讯飞智作 网页版

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      超级简历WonderCV 网页版
      超级简历WonderCV 网页版

      超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

      音述AI 网页版
      音述AI 网页版

      音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

      AionClaw macOS版
      AionClaw macOS版

      AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

      Loomy macOS版
      Loomy macOS版

      Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

      AirBuddy 3 macOS版
      AirBuddy 3 macOS版

      AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

      AirServer macOS版
      AirServer macOS版

      AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

      AnyDesk macOS版
      AnyDesk macOS版

      AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

      WINDOWS 更多
      讯飞绘文 网页版
      讯飞绘文 网页版

      讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

      Maya(Autodesk Maya) Windows版
      Maya(Autodesk Maya) Windows版

      Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

      Aperty Windows版
      Aperty Windows版

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      火山引擎 网页版
      火山引擎 网页版

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      立刻MV 网页版
      立刻MV 网页版

      立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

      蛙蛙写作 网页版
      蛙蛙写作 网页版

      蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

      讯飞智作 网页版
      讯飞智作 网页版

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      超级简历WonderCV 网页版
      超级简历WonderCV 网页版

      超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

      音述AI 网页版
      音述AI 网页版

      音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

      AionClaw Windows版
      AionClaw Windows版

      AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

      Loomy Windows版
      Loomy Windows版

      Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

      AirServer Windows版
      AirServer Windows版

      AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。

      即将离开本站
      您即将前往第三方网站,请确认是否继续?