redis实战---分布式锁--单机篇
redis分布式锁
- 故事背景
- 什么是Redis分布式锁
- 业务场景
- 未加任何锁的代码
- 单机情况下JVM级别加锁
- 多服务部署
- 总结提升
故事背景
本篇文章是redis实战系列的第二篇文章。本章的主要内容是Redis分布式锁的相关知识。本篇文章将告诉你什么是分布式锁,结合一个业务场景,先带大家看看,单机上是如何实现锁功能的。学完本篇,你可以了解到什么是锁,为什么要加锁。
什么是Redis分布式锁
Redis分布式锁是一种基于Redis实现的分布式锁机制,它可以保证在分布式环境中,同一时刻只有一个客户端能够获取到锁,从而避免了多个客户端同时对同一资源进行修改的问题。

接下来我将结合一个秒杀的例子讲述如果实现Redis的分布式锁。
业务场景
秒杀场景是一个非常经典的需要使用锁的场景。
假设有一个商品限时秒杀的业务场景,多个用户同时在秒杀开始时间内尝试购买该商品,但是该商品数量有限,只有一定数量的用户可以购买成功,其他用户则购买失败。
为了保证秒杀的公平性与真确性,这个时候我们就要通过锁来对商品的数量进行访问
未加任何锁的代码
结合上面的业务场景,我们来先来实现一个未加任何锁的代码,简单实现一下这个小需求:
- 首先在redis里添加了 key值为 stock value值 为 200 的数据,模拟我们要秒杀的商品数量为200

2.编写业务逻辑代码
@RestController
@RequestMapping("/test")
public class IndexController {// 自动注入 StringRedisTemplate 对象@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 处理 HTTP GET 请求路径是 /test/lock@GetMapping("lock")public String deductStock() {// 获取当前库存String stock1 = stringRedisTemplate.opsForValue().get("stock");if( stock1 == null){System.out.println("秒杀未开始");return "end";}int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stock > 0) {// 扣减库存int realStock = stock - 1;// 更新库存stringRedisTemplate.opsForValue().set("stock", realStock + "");System.out.println("扣减成功,剩余的库存为:" + realStock);} else {System.out.println("扣减失败,库存不足");}return "end";}}
上述是根据我们的业务进行的一个简单的实现,在这个实现里,未对代码进行加锁。这段代码将会出现很经典的超卖问题。我们来压测一下接口,看一下效果
3. 接口压测,模拟并发

在这里我们使用的ApiPost进行一键压测。让我们一起来看一下结果吧

我们发现,50个请求进来之后,如果是正常的情况下,是应该减少50个库存,每个请求获得1个商品。可以根据结果看,我们的50个请求获得了5个商品。同一个商品卖给了多个用户。列如 195号商品同时卖给了10个人。
那么我们该如何去解决这个问题呢?
单机情况下JVM级别加锁
首先我们来看一下,如果是单机(项目只部署在一台机器上),如何给我们的代码加锁,解决上述问题。
使用 synchronized 进行jvm级别加锁。
- 代码
synchronized (this){// 获取当前库存String stock1 = stringRedisTemplate.opsForValue().get("stock");if( stock1 == null){System.out.println("秒杀未开始");return "end";}int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stock > 0) {// 扣减库存int realStock = stock - 1;// 更新库存stringRedisTemplate.opsForValue().set("stock", realStock + "");System.out.println("扣减成功,剩余的库存为:" + realStock);} else {System.out.println("扣减失败,库存不足");}}
代码非常的简单,使用 synchronized 关键字,将我们的业务逻辑进行包裹即可。
synchronized,保证同一时刻只有一个线程执行被synchronized修饰的代码块或方法,从而避免多个线程同时对共享资源进行修改而导致的数据不一致的问题。
2. 运行结果

从结果上来看,通过synchronized 可以在jvm级别上进行上锁。但是我们实际的生产环境中,很少有部署单机服务的。如果我们部署了多个服务,那么通过synchronized 是肯定无法影响另一条机器上的请求的。
多服务部署

假设我们,部署了两个服务,部署在tomcat1和tomcat2上,使用nginx做负载。此时仅仅通过synchronized 只能保持 tomcat1自己本身。tomcat2自己本身的数据被锁住。如果两个服务同时提供服务,仍然会产生我们上述的超卖问题。
总结提升
本文我们主要讲了锁的概念,为什么要加锁,单机上jvm级别的加锁,多服务部署的话,我们现在的代码存在的问题。接下来我会讲解如何解决我们这次遗留的问题,在分布式环境下,如何加锁,如何解决可能会存在的问题。
专栏地址
相关文章:
redis实战---分布式锁--单机篇
redis分布式锁故事背景什么是Redis分布式锁业务场景未加任何锁的代码单机情况下JVM级别加锁多服务部署总结提升故事背景 本篇文章是redis实战系列的第二篇文章。本章的主要内容是Redis分布式锁的相关知识。本篇文章将告诉你什么是分布式锁,结合一个业务场景&#x…...
Java正则表达式
Java 正则表达式 文章目录Java 正则表达式捕获组正则表达式语法Matcher 类的方法索引方法查找方法替换方法start 和 end 方法matches 和 lookingAt 方法replaceFirst 和 replaceAll 方法appendReplacement 和 appendTail 方法PatternSyntaxException 类的方法正则表达式是对字符…...
MySQL数据库之——高级[进阶]SQL语句(二)正则表达式和存储过程
文章目录一、正则表达式(REGEXP)1、正则表达式匹配符2、语法二、存储过程1、概述2、优点3、 创建、调用、查看和删除存储过程4、存储过程的控制语句一、正则表达式(REGEXP) 1、正则表达式匹配符 2、语法 SELECT 选项 FROM 表名 …...
Python基于周立功盒子的二次开发的准备工作
Python基于周立功盒子的二次开发的准备工作 一、基本介绍 基于周立功的二次开发是python通过调用zlgcan.dll,来实现CAN卡的通讯收发报文的,在python中通过ctypes模块调用c++动态库的接口函数(zlgcan.dll),我们需要根据我的电脑选择相对应版本的dll,比如64位的操…...
2023年PMP考生|考前必练全真模拟题分享,附答案解析
“日日行,不怕千万里;常常做,不怕千万事。”每日五题,备考无压力! 1、敏捷项目以价值为驱动交付,确定好所有待办事项的价值进而去制造可交付成果。那么在整个敏捷项目周期中,衡量团队交付的可交…...
Python入门教程+项目实战-7.1节: 条件控制结构
目录 7.1.1 理解条件控制 7.1.2 if,elif,else 7.1.3 条件表达式 7.1.4 条件控制可以嵌套 7.1.5 if语句的三元运算 7.1.6 系统学习python 7.1.1 理解条件控制 在日常生活中,我们常喜欢说如果, "如果怎么样,那么就会怎么样"。"如果&…...
【机器学习】P4 特征缩放与学习率
这里写自定义目录标题特征缩放标准化归一化平均值归一化收敛学习率特征缩放 特征缩放(Feature scaling)是一种数据预处理技术,它用于将不同尺度的特征值缩放到相同的范围内,以便更好地应用于机器学习算法中。在不进行特征缩放的情…...
《Python编程:从入门到实战》(第2版)学习笔记 第11章 测试代码
【写在前面】为进一步提高自己的python代码能力,打算把几本经典书籍重新过一遍,形成系统的知识体系,同时适当记录一些学习笔记,我尽量及时更新!先从经典的《Python编程:从入门到实战》书籍开始吧。有问题欢…...
SpringBoot(1)基础入门
SpringBoot基础入门SpringBoot项目创建方式Idea创建SpringBoot官网创建基于阿里云创建项目手工搭建SpringBoot启动parentstarter引导类内嵌tomcat基础配置属性配置配置文件分类yaml文件yaml数据读取整合第三方技术整合JUnit整合MyBatis整合Mybatis-Plus整合DruidSpringBoot是由…...
利用Flow Simulation快速经济高效地解决传热难题
几乎一切事物都会经历某种程度的发热或冷却,而且对于许多产品来说,热管理已成为避免过度发热和实现功能正常运行的一个关键要求。能够有效解决传热问题的制造商将会在竞争中占有明显的优势。利用一个简单易用的流体分析应用程序 SOLIDWORKS Flow Simulat…...
揭开二维码背后的神秘面纱用二维码识别 API 就够了
写在前面 二维码(QR code)已经成为现代生活中不可或缺的一部分。二维码具有可靠性、快速识别、易于存储等优点,因此在广泛应用于支付、门票、社交网络、广告等方面。但是,对于大多数人来说,二维码背后的编码方式是完全…...
系统分析——系统构建最重要的一环
🌟所属专栏:信息系统分析与设计 🐔作者简介:rchjr——五带信管菜只因一枚 😮前言:该系列将持续更新信息系统分析与设计课程的相关学习笔记,欢迎和我一样的小白订阅,一起学习共同进步…...
第1-第20个高级shell程序
高级shell脚本 1.使用Shell脚本批量修改文件名 #!/bin/bash for fi lein$(ls*.txt) do mv $file${file%%.*}.md done2.统计一个文本文件中某个单词出现的次数 #!/bin/bashword"example" count0 whilereadline do forwin$line do if["$w""$word&qu…...
【致敬嵌入式攻城狮第2期活动预热征文】学习安排
文章目录「 致敬未来的攻城狮计划 」——学习计划前言学习计划🚗单片机理论实践🚗学业阅读计划「 致敬未来的攻城狮计划 」——学习计划 🚀🚀开启攻城狮的成长之旅!这是我参与的由 CSDN博客专家 架构师李肯和 瑞萨MCU …...
035:cesium加载KML文件,显示图形
第035个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载KML文件, 显示图形。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共83行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:https:/…...
随想录Day42--动态规划: 416. 分割等和子集(终于吃下01背包了)
今天只有1道题,属于动态规划的01背包问题的应用。首先理解一下动态规划的01背包问题。推荐一个视频,动态规划DP0-1背包,这是我认为讲得最为通透的。很多讲解动态背包问题的,一上来就画二维表格,遍历背包或者遍历容量&a…...
字节跳动软件测试岗,前两面过了,第三面被面试官吊打,结局我哭了
阎王易见,小鬼难缠。我一直相信这个世界上好人居多,但是也没想到自己也会在阴沟里翻船。我感觉自己被字节跳动的HR坑了。 在这里,我只想告诫大家,offer一定要拿到自己的手里才是真的,口头offer都是不牢靠的࿰…...
bitlocker 笔记
介绍 bitlocker是windows自带的磁盘加密工具,win10专业版是可以使用的,其他家庭版本可能没有这个功能。有点类似与wd security。 功能 加密磁盘,当磁盘物理丢失时,防止磁盘中的数据泄露。举个例子,移动硬盘被偷&…...
Linux 压缩与解压命令
一、常见的压缩文件扩展名 1、*.Z compress程序压缩的文件 2、*.gz gzip程序压缩的文件 3、.tar.gz tar程序打包的文件,其中经过gzip的压缩 4、.tar tar程序打包的数据,并没有压缩过 5、.bz2 bzip2程序压缩的文件 6、.tar.bz2 tar程序打包的文件&a…...
python global函数用法及常用的 global函数代码
Python中的 global函数是用于在程序中定义变量的函数,在我们实际的开发中,我们可能会用到 global函数来定义变量,但是我们在这里就不具体介绍它的用法了。 global函数定义变量的方法: global函数使用参数a来指定变量在程序中的地址…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
