面试必备:聊聊互斥锁、自旋锁、读写锁、悲观锁、乐观锁使用场景

llovebo

共 1583字,需浏览 4分钟

 ·

2021-11-04 00:29

 先来聊聊为啥加锁,多线程访问共享资源的时候,为了避免资源竞争而导致数据错乱,会在访问共享资源之前加锁,加锁的目的是保证共享资源在任意时间里,只有一个线程访问。锁又分为互斥锁、自旋锁、读写锁、悲观锁、乐观锁,下面分别介绍使用场景。

  1、互斥锁

  互斥锁是一种【独占锁】,当线程A加锁成功后,此时互斥锁已经被线程A独占了,只要线程A没有释放手中的锁,线程B加锁就会失败,于是就会释放CPU让给其他线程,既然线程B释放掉了CPU,自然线程B加锁的代码就会被阻塞。

2、自旋锁

自旋锁是通过CPU提供的CAS函数(Compare And Swap),在【用户态】完成加锁和解锁操作,不会主动产生线程上下文切换,所以相比互斥锁来说,会快一些,开销也小一些。比较简单的一种锁,一直自旋,利用CPU周期,直到锁可用。需要注意,在单核CPU上,需要抢占式的调度器(即不断通过时钟中断一个线程,运行其他线程)。否则,自旋锁在单CPU上无法使用,因为一个自旋的线程永远不会放弃CPU。


3、读写锁

读写锁从字面意思我们也可以知道,它由【读锁】和【写锁】两部分构成,如果只读取共享资源用【读锁】加锁,如果要修改共享资源则用【写锁】加锁。所以,读写锁适用于能明确区分读操作和写操作的场景。

 工作原理:当【写锁】没有被线程持有时,多个线程能够并发地持有读锁,这大大提高了共享资源的访问效率,因为【读锁】是用于读取共享资源的场景,所以多个线程同时持有读锁也不会破坏共享资源的数据。

      但是,一旦【写锁】被线程持有后,读线程的获取读锁的操作会被阻塞,而且其他写线程的获取写锁的操作也会被阻塞。

所以说,写锁是独占锁,因为任何时刻只能有一个线程持有写锁,类似互斥锁和自旋锁,而读锁是共享锁,因为读锁可以被多个线程同时持有。


根据实现的不同,读写锁可以分为【读优先锁】和【写优先锁】。

读优先锁期望的是,读锁能被更多的线程持有,以便提高读线程的并发性,它的工作方式是:当读线程A先持有了读锁,写线程B在获取写锁的时候,会被阻塞,并且在阻塞过程中,后续来的读线程C仍然可以成功获取读锁,最后直到读线程A和C释放读锁后,写线程B才可以成功获取读锁。

而写优先锁是优先服务写线程,其工作方式是:当读线程A先持有了读锁,写线程B在获取写锁的时候,会被阻塞,并且在阻塞过程中,后续来的读线程C获取读锁时会失败,于是读线程C将被阻塞在获取读锁的操作,这样只有读线程A释放读锁后,写线程B就可以成功获取读锁。

读写锁适用于能明确区分读操作和写操作的场景

4、乐观锁和悲观锁


前面提到的互斥锁、自旋锁、读写锁,都是属于悲观锁。悲观锁认为多线程同时修改共享资源的概率比较高,于是很容易出现冲突,所以访问共享资源前,先要上锁。

乐观锁认为多线程同时修改共享资源的概率比较低,它的工作方式是:先修改完共享资源,再验证这段时间内有没有发生冲突,如果没有 其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作。

乐观锁虽然去除了加锁解锁的操作,但是一旦发生冲突,重试的成本非常高,所以只有在冲突概率非常低,且加锁成本非常高的场景时,才考虑使用乐观锁。


参考:

https://www.cnblogs.com/everydaystarting123/p/13959630.html


版权申明:本文来源于网友收集或网友提供,仅供学习交流之用,如果有侵权,请转告版主或者留言,本公众号立即删除。


支持小微:

腾讯云 双十一活动!玩服务器的可以搞搞!

轻量服务器  1C2G5M 50GB SSD盘 50元起

链接:https://curl.qcloud.com/bR8ycXZa


右下角,您点一下在看图片2f6310d55640b6da95c7dbfd9bea0bad.webp

小微工资涨1毛

商务合作QQ:185601686



浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报