【Redis】利用 Redis 实现分布式锁

SpringBoot整合Redis实现分布式锁 一、什么是分布式锁? 在多线程程序中,不予许多个线程同时操作某个变量或者同时执行某一代码块,我们就需要用锁来实现。在Java中,可以用synchronized或Lock接口的实现类来实现。那么什么是分布式锁呢?当我们的应用通过分布式部署,每个应用部署在不同的机器上,但是我们要保证这些不同机器上的同一方法在同一时间不能被多个线程执行,这时候就要用到分布式锁。 二、实现分布式锁的几种方式 1.基于数据库实现分布式锁 2.基于Redis实现分布式锁 3.基于zoomkeeper 分布式锁有很多种实现方 阅读详情

技术背景

首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁。

对于这个问题,我们可以简单将锁分为两种——内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关键字(或许加上进程级锁修饰更恰当些),而分布式锁则是应用在分布式系统中的一种锁机制。分布式锁的应用场景举例以下几种:

  • 互联网秒杀
  • 抢优惠卷
  • 接口幂等校验

文章相关视频讲解:

线程锁、进程锁以及分布式锁的实现

如何高效学习使用redis

Linux后端开发网络底层原理知识学习点击观看:c/c++Linux后台服务器开发高级架构师学习视频资料

我们接下来以一段简单的秒杀系统中的判断库存及减库存来描述下为什么需要到分布式锁:

Copypublic String deductStock() throws InterruptedException {
    
    // 1.从 Redis 中获取库存值
    int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
    // 2.判断库存
    if (stock > 0) {
        int readStock = stock - 1;
        // 3.从新设置库存
        stringRedisTemplate.opsForValue().set("stock", realStock + ""); 
        System.out.println("扣减成功,剩余库存:" + readStock + "");
    } else {
        System.out.println("扣减失败,库存不足");
    }
    
    return "end";
}

上面这段代码中,实现了电商系统中的一个简单小需求,即判断商品的剩余数量是否充足,充足则可以成功卖出商品,并将库存减去 1。我们很容易了解这段代码的目的。接下来我们就来一步一步地分析这段代码的缺陷。

基本实现

原子性问题

上面代码中的注释1~3部分,并没有实现原子性的逻辑。所以假设现在如果只剩下一件商品,那么可能会出现以下情况:

  • 线程 A 运行到代码2,判断库存大于0,进入条件体中将 stock - 1 赋值给 readStock,在执行代码 3 前停止了下来;
  • 线程 B 同样运行到代码2,判断出库存大于0(线程A并没有写回Redis),之后并没有停止,而是继续执行到方法结束;
  • 线程 A 此时恢复执行,执行完代码 3,将库存写回 Redis。

现在我们就发现了问题,明明只有一件商品,却被两个线程卖出去了两次,这就是没有保证这部分代码的原子性所带来的安全问题。

那对于这个问题如何解决呢?

常规的方式自然就是加锁以保证并发安全。那么以我们 Java 自带的锁去保证并发安全,如下:

Copypublic Synchronized String deductStock() throws InterruptedException {    
    // 业务逻辑...
}

我们知道 synchronized 和 Lock 支持 JVM 内同一进程内的线程互斥,所以如果我们的项目是单机部署的话,到这里也就能保证这段代码的原子性了。不过以互联网项目来说,为了避免单点故障以及并发量的问题,一般都是以分布式的形式部署的,很少会以单机部署,这种情况就会带来新的问题。

分布式问题

刚刚我们将到了如果项目分布式部署的话,那么就会产生新的并发问题。接下来我们以 Nginx 配置负载均衡为例来演示并发问题,同样的请求可能会被分发到多台服务器上,那么我们刚刚所讲的 synchronized 或者 Lock 在此时就失效了。同样的代码,在 A 服务器上确实可以避免其他线程去竞争资源,但是此时 A 服务器上的那段 synchronized 修饰的方法并不能限制 B 服务器上的程序去访问那段代码,所以依旧会产生我们一开始所讲到的线程并发问题。

 

那么如何解决掉这个问题呢?这个是否就需要 Redis 上场了,Redis 中有一个命令SETNX key value,SETNX 是 “SET if not exists” (如果不存在,则 SET)的缩写。那么这条指令只在 key 不存在的情况下,将键 key 的值设置为 value。若键 key 已经存在,则 SETNX 命令不做任何动作。

有了上面命令做支撑,同时我们了解到 Redis 是单线程模型(不要去计较它的网络读写和备份状态下的多线程)。那么我们就可以这么实现,当一个服务器成功的向 Redis 中设置了该命令,那么就认定为该服务器获得了当前的分布式锁,而其他服务器此时就只能一直等待该服务器释放了锁为止。我们来看下代码实现:

Copy// 为了演示方便,这里简单定义了一个常量作为商品的id
public static final String PRODUCT_ID = "100001";

public String deductStock() throws InterruptedException {

    // 通过 stringRedisTemplate 来调用 Redis 的 SETNX 命令,key 为商品的id,value的值在这不重要
    Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(RODUCT_ID, "jojo");
    if (!result) {
        return "error";
    }

    int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
    if (stock > 0) {
        int readStock = stock - 1;
        stringRedisTemplate.opsForValue().set("stock", realStock + ""); 
        System.out.println("扣减成功,剩余库存:" + readStock + "");
    } else {
        System.out.println("扣减失败,库存不足");
    }

    // 业务执行完成,删除PRODUCT_ID key
    stringRedisTemplate.delete(PRODUCT_ID);
    
    return "end";
}

到这里我们就成功地利用 Redis 实现了一把简单的分布式锁,那么这样实现是否就没有问题了呢?

锁释放问题

生产环境比我们想象中要复杂

利用Redis实现分布式锁 利用Redis实现分布式锁 在之前的答题对战项目中,游戏规则是根据双方回答同一道题所花时间长短判胜负,但测试过程中遇到一个偶现BUG:“对战开始后双方收到的题目不一致”,经过分析代码,发现问题原因在于发题逻辑没有加锁,所以写篇文章聊聊这个话题。 什么是锁 在编程领域,锁是一种用来做独占代码执行的方式,通俗来讲就是在打算做某件事情之前要申请许可证,如果没有得到许可证则无法做这件事。需要许可证的原因是... 阅读详情

相关推荐

Java利用Redis实现分布式锁(核心代码实现)

        摘要:读完本章您将知道如何利用Redis设计分布式锁        在Java中利用Redis实现分布式锁主要利用jedis API(Jedis类) 提供的以下几个方法:        Long setnx(final byte[] key, final byte[] value);        往redis服务器中设置值,如果key已存在,设置失败返回0;如果key不存在,设置...

言必信,行必果 3499

保姆级教程:用Docker快速部署mpromonet/webrtc-streamer实现WebRTC直播(附常见问题解决)

本文提供了一份详细的Docker部署mpromonet/webrtc-streamer的实战指南,帮助用户快速搭建WebRTC直播服务。内容涵盖从环境准备、基础部署到进阶配置与性能调优的全过程,并针对容器网络、视频流配置、跨网访问等常见问题提供了解决方案,旨在实现低延迟的流媒体传输。

dell8的博客 175

Linux新手必看:FinalShell连接不上?从检查IP到配置固定地址的完整排错指南

本文为Linux新手提供了FinalShell连接失败的完整排错指南,涵盖IP检查、SSH服务状态、防火墙配置和静态IP设置等关键步骤。通过详细的命令行操作和配置示例,帮助用户快速解决远程连接问题,提升Linux使用效率。

weixin_30675247的博客 753

告别编译报错!手把手教你用VS2022命令行编译curl静态库(附完整测试代码)

本文详细介绍了如何在VS2022环境下通过命令行编译curl静态库,从环境准备、编译实战到项目集成,提供了完整的避坑指南和测试代码。特别针对常见的编译报错如LNK2019等给出了具体解决方案,帮助开发者高效完成网络库的静态编译与集成。

weixin_42557803的博客 446

【数学模型】灰色关联分析

数学模型-灰色关联分析

suic009的博客 1万+

从ISCXTor2016到CICIDS2017:手把手教你下载和使用UNB的网络安全数据集

本文详细介绍了UNB大学发布的ISCXTor2016和CICIDS2017等网络安全数据集的下载与使用方法,特别适合加密流量识别和网络行为分析研究。文章提供了多种高效获取路径、文件结构解析及实战分析示例,帮助研究者快速上手这些真实场景捕获的精细标注数据集。

weixin_42524945的博客 629

AI辅助游戏开发实战:Kimi K3提升Unity开发效率与代码质量

在游戏开发领域,有限状态机(FSM)是构建角色AI行为逻辑的核心设计模式,它通过定义明确的状态和转换条件,使游戏实体能够智能地响应环境变化。其原理在于将复杂的行为分解为离散的状态节点,并通过事件驱动状态切换,从而实现清晰、可维护的AI架构。这项技术的价值在于显著提升了游戏角色的行为真实感和开发效率,被广泛应用于NPC行为控制、角色动画管理、UI流程等场景。随着AI编程助手的兴起,开发者现在可以借助如Kimi K3这类工具,通过自然语言指令快速生成和优化FSM等复杂系统的代码框架,将更多精力投入到核心玩法与性

weixin_30430677的博客 406

ArcGIS License Server点击启动没反应,许可管理器无法启动怎么办

4 当我们再打开ArcGIS License Server Administrator的时候。3 在【服务】中找到【ArcGIS License Manager】双击。无法启动ArcGIS License Server的情况。在使用ArcGIS的过程中,我们经常会遇到。专注GIS领域知识分享,交流行业软件技巧。欢迎关注,不定期分享GIS各种问题和技巧。1 右击我的电脑——【管理】服务状态——启动,确定即可。启动类型选择——自动。

GIS蒲公英的博客 2万+

TTL转RS422(B)工业级转换模块设计:从原理到实战部署

在工业自动化与嵌入式系统中,串行通信是实现设备间数据交换的基础。其核心原理在于通过特定的电气标准与协议,将数据位序列化后进行传输。RS422作为一种差分平衡传输协议,相比常见的TTL电平,在抗共模干扰与远距离传输能力上具有显著的技术优势,这使其成为工业现场总线、楼宇自动化等对可靠性要求严苛场景的优选方案。要实现TTL设备与RS422网络的稳定互联,关键在于设计一个能够完成单端信号到差分信号高质量转换的硬件模块。这涉及到差分总线收发器芯片的选型、包含终端电阻与TVS二极管的保护电路设计,以及遵循差分走线规则的

weixin_29195615的博客 340

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

上一篇: 开发过程中程序员非常烦恼的问题,3种内存泄漏的解决方案
下一篇: 亿级流量架构之网关设计思路、常见网关对比
Linux服务器开发
博客等级 码龄7年 609粉丝 589原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值