• 线程锁(ReentrantLock、synchronized)为何不能用作分布式锁


    为什么使用分布式锁

    分布式锁实现目前有三种:

    • 数据库乐观锁;
    • ZooKeeper的分布式锁;
    • Redis的分布式锁

    在以前单体架构Web应用场景下,我们可以使用ReentrantLock或synchronized进行上锁,保证资源安全,现如今大部分Web应用都采用分布式架构,分布式架构可以简单理解为将一个Web应用,部署在多个应用服务器上
    在这里插入图片描述由于分布在不同服务器上,这将使原单体架构使用的锁(例如synchronized)失效,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这时就需要使用分布式锁

    分布式锁适用于分布式架构场景,例如:

    • 商品秒杀
    • 抢优惠卷

    平时开发过程中,如果没有保证线程安全,就可能会出现商品超卖、优惠卷发超等现象,例如下图代码:
    在这里插入图片描述
    我们会判断商品库存是否大于0,如果有库存就会将库存 - 1,不过有个问题,如果同时有多个用户(多线程)同时发送请求给接口,例如三个用户同时请求接口,同时获取商品库存、扣除库存,很有可能商品库存最终只扣除1次,这时候数据安全性就得不到保障了,线程安全问题发生的本质是多线程访问同一临界区进行上下文切换,最终导致指令交错

    2、synchronized为何不能用作分布式锁

    想要解决线程安全问题,我们首先想到的是synchronized,通过此方法来保障某一时刻,只有一个线程拿到锁资访问接口,如果是单体架构项目通过这种方式是可以的(功能可以保证,但是性能很差)。
    在这里插入图片描述
    现如今,大多数Web应用使用的是分布式部署,需要使用多个服务器(例如Tomcat)进行分布式部署,Nginx对我们的服务器集群做反向代理负载均衡,那这种分布式架构场景使用synchronized会不会有问题?会!
    在这里插入图片描述
    为什么分布式场景使用synchronized依然会出现线程安全问题?
    因为synchronized是JVM进程级别的锁,由于分布式部署原因,同样的synchronized代码块内容在不同的服务器(tomcat1和tomcat2)运行时,抢占的的不是同一把锁。所以当多个请求通过Nginx分发到不同的tomcat服务器,此时synchronized没办法保证线程安全问题,因为图中这两台tomcat上的synchronized使用的不是同一个锁,就没办法保证线程安全,这时就需要使用分布式锁!

    总结:
    因为进程具有独立性,各个进程(tomcat)无法访问其他进程的资源,因此无法通过synchronized等线程锁实现线程安全
    分布式场景保证线程安全,尽量不要使用synchronized(并发低情况勉强可以使用),应该使用分布式锁,例如:Redisson
    在这里插入图片描述

    3、使用Redisson实现分布式锁

    redis实现分布式锁底层是基于命令:SET key value NX EX max-lock-time

    使用Redisson保证分布式场景下线程安全问题,代码如下:
    在这里插入图片描述
    Redisson分布式锁实现原理:
    在这里插入图片描述

  • 相关阅读:
    python中使用缓存技术
    QLineEdit 类(行编辑器)
    Vue-admin-template新增TagViews标签页功能,附完整代码
    开源的价值观与文化的传递
    【附源码】Python计算机毕业设计社区团购系统
    Nginx实现本地http转https请求
    不到20W纯电SUV提回家,到店实拍2022款奇瑞大蚂蚁
    XUI - 一个简洁而优雅的Android原生UI框架
    关于#java#的问题,请各位专家解答!
    对象分配规则
  • 原文地址:https://blog.csdn.net/weixin_46594796/article/details/124836090