面试必备:聊聊互斥锁、自旋锁、读写锁、悲观锁、乐观锁使用场景
共 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
右下角,您点一下在看图片
小微工资涨1毛
商务合作QQ:185601686