• 线程锁(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分布式锁实现原理:
    在这里插入图片描述

  • 相关阅读:
    【UCB操作系统CS162项目】Lab0:项目上手 (Getting Real)
    一网打尽——线粒体基因组高级分析
    .NET JIT
    ARM Codec要求
    《红蓝攻防对抗实战》八.利用OpenSSL对反弹shell流量进行加密
    阿里技术大牛亲自编写,将高难度的 Java 高并发知识讲解得浅显易懂
    nothing to repeat at position 0(解决方案)
    【软考】14.2 统一建模语言UML/事务关系图
    DNS常用术语介绍
    小白学java
  • 原文地址:https://blog.csdn.net/weixin_46594796/article/details/124836090