• 枪出惊龙,众“锁”周之


    枪出惊龙,众“锁”周之

    1.为什么要上锁?锁的意义是什么?

    1 多线程访问共享数据,保证数据的安全
    2 他会降低并发量,但是他能保证数据的安全

    问题:秒杀本来是高并发的场景,你加锁了,会不会降低效率?降低了,那你加锁的意义在哪里?

    2. 锁的分类

    2.1 公平锁和非公平锁

    公平锁:顾名思义,他是公平的,按照先来先到的顺序依次执行;比如秒杀
    非公平锁:每次线程获取到锁的顺序,和他们申请的顺序不一致,有可能后来居上,后来的线程,反而先拿到锁;

    2.2 轻量级锁和重量级锁

    轻量级锁:在程序运行内部就可以处理
    重量级锁:程序内部已经无法处理,交由操作系统进行管理

    2.3 排它锁和共享锁/读锁和写锁

    • 排它锁,又称为独占锁,或者写锁
      • 概念:指该锁一次只能被一个线程所持有。
      • JavaSE:对ReentrantLock和Synchronized而言都是独占锁。
      • MySql:使用方式:SELECT * FROM table_name WHERE … FOR UPDATE,使用场景:并发下对商品库存的操作
    • 共享锁,又称为读锁
      • 概念:该锁可以被多个线程持有;
      • JavaSE:对ReentrantReadWriteLock,其读锁是共享锁,其写锁是独占锁。读锁的共享锁可保证并发读是非常高效的。
      • MySql:使用方式:SELECT * FROM table_name WHERE … LOCK IN SHARE MODE;使用场景:即事务A 使用共享锁 获取了某条(或者某些)记录时,事务B
        可以读取这些记录,可以继续添加共享锁,但是不能修改或删除这些记录

    2.4偏向锁和自旋锁

    偏向锁:加锁时,锁的标志位直接记录加锁的这条线程PID;偏向锁不会自动释放,下次当这条PID线程来继续使用这个资源的时候,无需争抢,直接获取锁
    自旋锁:轻量级锁通过自旋的方式等待资源

    2.5 类锁和对象锁

    类锁:只有一个,类锁锁的是Class对象
    对象锁:无数个,对象锁锁的是实例对象

    在这里插入图片描述

    2.6 表锁和行锁

    主要指的是数据库中
    表锁:锁的是整张表
    行锁:锁的是这一行数据

    2.7 分布式锁-Redission分布式锁

    在这里插入图片描述

    • 为什么要使用lua语言
      因为一大堆复杂的业务逻辑,可以通过封装在lua脚本中发送给redis,保证这段复杂业务逻辑执行的原子性

    • 为什么要设置锁的过期时间?

      Redis分布式锁,一旦客户端没有释放锁,服务端就会一直持有这个锁的,其他进程中的线程是获取不了锁的,从而出现死锁。
      比如以下这两种情况:
      1.网络抖动 进程A中的一个线程获取到了锁,然后执行finally中的释放锁的代码时,由程序到Redis的网络不好了,所以释放锁失败。此时对于redis服务端来说,它可不知道客户端曾经试图释放过锁,它会一直把锁给A,如此一来,其他进程的线程再也不能获取到这个锁了。
      如果用设置过期时间的方式,即使客户端和服务端的网络不通了,服务端依然在进行时间的计算,时间到了直接把锁释放掉,等网络通了,不影响获取锁。
      2.服务端宕机 进程A获取到了锁,Redis服务器宕机了,所以锁没有释放。等到Redis再次恢复的时候,Redis服务端还会保持这这个锁给到A,就会锁死。
      如果是设置了过期时间的话,服务器恢复后就会继续倒计时,时间到了服务器自动把锁释放。

    • 看门狗策略是啥?
      1、客户端1加锁的默认生存时间是30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?
      Redisson中客户端1一旦加锁成功,就会启动一个watch
      dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。
      2、如果负责存储这个分布式锁的Redission节点宕机后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态,为了避免这种情况的发生,Redisson提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。

    2.8 synchronized锁升级的机制/过程

    在这里插入图片描述

    1. jdk1.5以前,synchronized就是重量级锁,一旦发生多线程争抢资源,直接交给操作系统处理,但是效率低下
    2. jdk1.5以后,synchronized有锁升级的过程:
      • 无锁:没有被线程加锁的时候,这就是一个普通对象
      • 偏向锁:加锁时,锁的标志位直接记录加锁的这条线程PID,偏向锁不会自动释放,下次当这条PID线程来继续使用这个资源的时候,无需争抢,直接获取锁
      • 轻量级锁:多个线程争抢同一把锁,轻量级锁会进入自旋状态,此时也称为自旋锁
      • 重量级锁:当轻量级锁默认自旋10次,升级为重量级锁

    2.9 synchronized是公平锁还是非公平锁?是轻量级锁还是重量级锁?

    非公平锁 在jdk1.5的时候是重量级锁 交给操作系统去管理
    在jdk1.6之后变为轻量级锁 走程序内部 不行再切换到操作系统 是可重入锁

    2.10 lock(ReententLock)锁是公平锁还是非公平锁?是轻量级锁还是重量级锁?

    lock可以是公平锁,也可以是非公平锁,主要通过设置fair变量,fair=true,设置公平锁,fair=false,设置非公平锁
    lock就是轻量级的锁

    在这里插入图片描述

    2. 11 synchronize原理

    在这里插入图片描述
    通过反编译,我们看到了monitor_enter(监视器入口)和monitor_exit(监视器出口),线程在获取monitor(监视器)前,会先查看monitor的进入数是否为0,如果是0则获取锁,进入数+1,线程成为monitor的拥有者,其他线程想要进入的话,就会进入阻塞状态,此时如果拥有monitor的线程再次进入的话,进入数还会继续+1,所以说,monitor是可以重复进入的。monitor_exit只有monitor拥有者才可以调用,调用一次,monitor的进入数-1,当montior=0的时候,释放锁。

  • 相关阅读:
    为什么用公钥加密却不能用公钥解密?
    设计模式——中介者模式
    关于云主机root无法从VNC登录处理
    你能猜出这是什么代码吗
    虚假内容检测,谣言检测,不实信息检测,事实核查;纯文本,多模态,多语言;数据集整理
    UDP协议深度解析:从原理到应用全面剖析
    yml文件构建容器
    贪心-加油站
    如何用chatGTP function calling 写sql query,附代码!
    Docker 的数据管理与Docker 镜像的创建
  • 原文地址:https://blog.csdn.net/weixin_45854212/article/details/125513330