当前位置:网站首页>枪出惊龙,众“锁”周之

枪出惊龙,众“锁”周之

2022-07-07 08:29:00 孤礬

枪出惊龙,众“锁”周之

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的时候,释放锁。

原网站

版权声明
本文为[孤礬]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_45854212/article/details/125513330