当前位置: 首页 > news >正文

分布式锁介绍与实现

相信大家经常听到分布式锁这个东西,但可能并不太了解,接下来我们通过解决问题的方式来了解分布式锁

现在要实现一个秒杀功能:

    public void placeOrder() throws InterruptedException {Long stock = Long.parseLong(redisTemplate.opsForValue().get("stock"));if(stock > 0) {Thread.sleep(100);redisTemplate.opsForValue().set("stock", String.valueOf(--stock));System.out.println(Thread.currentThread().getName() + "秒杀成功");}else{System.out.println(Thread.currentThread().getName() + "秒杀失败,库存不足");}}@RequestMapping("/main")public void main(String[] args) {for(int i = 0; i < 3; i++) {new Thread(() -> {try {placeOrder();} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();}}

上面代码很明显存在超卖的问题,我们运行也可也看到(这里提前在redis中加入了stock,值为1):

解决方案我们也很容易想到,那就是加锁:

    public static Long stock = 1L;public static synchronized void placeOrder() throws InterruptedException {if(stock > 0) {Thread.sleep(100);stock--;System.out.println(Thread.currentThread().getName() + "秒杀成功");}else{System.out.println(Thread.currentThread().getName() + "秒杀失败,库存不足");}}public static void main(String[] args) {for(int i = 0; i < 3; i++) {new Thread(() -> {try {placeOrder();} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();}}

可以看到防止了超卖问题,

但是随着用户量日益增多,我们的系统出现了瓶颈,这时就可以使用负载均衡技术部署多个服务器,由于我们使用的同步锁只对当前服务器生效,多个服务之间的并发依然是不安全的,所以又会导致超卖问题。

这种情况下就需要分布式锁,具体实现我们可以使用Redis的setNX,这个命令表示只有当key不存在才会设置成功:

    public void placeOrder() throws InterruptedException {String productId = "acf435";//使用分布式锁,while(redisTemplate.opsForValue().setIfAbsent(productId, Thread.currentThread().getName(), Duration.ofSeconds(10))) {Long stock = Long.parseLong(redisTemplate.opsForValue().get("stock"));if(stock > 0) {Thread.sleep(100);redisTemplate.opsForValue().set("stock", String.valueOf(--stock));System.out.println(Thread.currentThread().getName() + "秒杀成功");}else{System.out.println(Thread.currentThread().getName() + "秒杀失败,库存不足");}//释放锁redisTemplate.delete(productId);break;};}

那么这里我们就可以使用商品id作为key,当需要操作某个商品时把商品id作为key存入redis,存入成功的则允许进行下一步操作,注意,这里一定要设置超时时间,如果某个服务器存入key成功后恰巧这个服务器挂了,那么这个key就无法被释放了,所以一定要设置过期时间。

这里还存在一个问题,就是,如果超过过期时间业务还没有处理完,那么key就被释放了,其它服务器就能够继续操作。对于这个问题,我们可以使用一个线程,每隔一段时间去探测一下当前处理服务的线程是否在线,在线则延长过期时间即可:

    public void placeOrder() throws InterruptedException {String productId = "acf435";Thread mainThread = Thread.currentThread();//使用分布式锁,while(redisTemplate.opsForValue().setIfAbsent(productId, Thread.currentThread().getName(), Duration.ofSeconds(10))) {//续命线程new Thread(() -> {//每隔5秒检测主线程是否在线,在线则延长key过期时间while (true) {try {Thread.sleep(5000);if(mainThread.isAlive()) {redisTemplate.opsForValue().setIfPresent(productId, mainThread.getName(), Duration.ofSeconds(10));}else{Thread.currentThread().interrupt();}} catch (InterruptedException e) {throw new RuntimeException(e);}}}).start();try {Long stock = Long.parseLong(redisTemplate.opsForValue().get("stock"));if (stock > 0) {Thread.sleep(100);redisTemplate.opsForValue().set("stock", String.valueOf(--stock));System.out.println(Thread.currentThread().getName() + "秒杀成功");} else {System.out.println(Thread.currentThread().getName() + "秒杀失败,库存不足");}break;}finally {//释放锁redisTemplate.delete(productId);}};}


文章转载自:

http://ITuN34nR.rwpfb.cn
http://Ckuz0ed5.rwpfb.cn
http://o39PdZYr.rwpfb.cn
http://HyMQ8qYn.rwpfb.cn
http://96qeC4Jn.rwpfb.cn
http://DxxW2Zt8.rwpfb.cn
http://ktIzBr9M.rwpfb.cn
http://obkS4uok.rwpfb.cn
http://aKieNUfW.rwpfb.cn
http://5399ITj0.rwpfb.cn
http://Wmf2q5RU.rwpfb.cn
http://xvvmfNTH.rwpfb.cn
http://5j7sSCi9.rwpfb.cn
http://SMf6gEnJ.rwpfb.cn
http://i8XcWgHu.rwpfb.cn
http://4nXfrt90.rwpfb.cn
http://DVV02WYv.rwpfb.cn
http://F6D4OGAz.rwpfb.cn
http://T8wxDbci.rwpfb.cn
http://ygyyghw7.rwpfb.cn
http://vGbGAMzo.rwpfb.cn
http://uXujYKGv.rwpfb.cn
http://6jL4wpIl.rwpfb.cn
http://qGlcFFck.rwpfb.cn
http://xRqF248E.rwpfb.cn
http://gM0dePT1.rwpfb.cn
http://F4MkcNXw.rwpfb.cn
http://w2ogak4i.rwpfb.cn
http://QdJ74TjT.rwpfb.cn
http://1CU2SV8e.rwpfb.cn
http://www.dtcms.com/a/382581.html

相关文章:

  • 海盗王客户端dx9的64位release版测试
  • MX模拟赛总结
  • FLEXSPI_Init 硬件故障问题
  • Linux进程概念(下):进程地址空间
  • C++11_3(智能指针篇)
  • 从理论到实践:构建高效AI智能体系统的架构演进
  • 如何运用好DeepSeek为自己服务:智能增强的范式革命 | 1.3 人机认知耦合协议
  • 什么是PV操作?
  • 详解数据仓库和数据集市:ODS、DW、DWD、DWM、DWS、ADS
  • C++ `std::unique_lock` 深度解析:掌控并发资源的智能管家
  • 人员主数据的系统集成
  • C++(静态函数)
  • SonarQube代码质量管理平台本地化搭建和使用
  • Redis 线上问题排查完整手册
  • 异常数据处理全攻略:原理、方法与Python实战
  • Python 进阶:从基础到实战的核心技能提升
  • Scikit-learn:从零开始构建你的第一个机器学习模型
  • 如何快速获取全机硬件详细参数?
  • 嵌入式ARM架构学习7——时钟、定时器
  • 【C++练习】17.C++求两个整数的最大公约数(GCD)
  • SQL-字符串函数、数值函数、日期函数
  • Redis内存回收:过期策略与淘汰策略
  • 【css学习笔记9】品优购项目
  • 动态规划解决网格路径问题
  • 金融科技:企业和机构银行
  • C++ 异常
  • One-hot encoding|独热编码
  • AI论文速读 | VisionTS++:基于持续预训练视觉主干网络的跨模态时间序列基础模型
  • 如何学习VBA_3.3.9:利用“搭积木”思想,快速有效地完成你的代码
  • 《使用深度学习统一时间相位展开框架》论文总结