悲观锁和乐观锁
最近面试都被问到这个,可是都只是靠着零散的记忆不知说了啥,那就好好整理一趟吧。
悲观锁:
当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人需改,最好的方法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制在修改数据之前先锁定,再修改的方式称之为悲观并发控制。之所以叫悲观锁,是因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据并发修改的概率比较大,所以在修改之前先加锁。悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全性提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还会增加产生死锁的机会,另外,还会降低并发性,一个事务如果锁定了某行数据,其他事物就必须等待该事物处理完才能处理那行数据。
乐观锁:
乐观锁是相对于悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发生了冲突,则返回用户错误的信息,让用户决定如何去做。相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般实现乐观锁的方式就是记录数据版本号。乐观并发控制相信事物之间的数据竞争的概率是比较小的,因此尽可能直接做下去,知道提交的时候才去锁定,所以不会产生任何锁和死锁。
高并发场景中,乐观锁和悲观锁哪个更合适?
因为乐观锁和悲观锁是在处理并发访问时使用的两种不同的策略。
参照上面的解析。乐观锁的基本思想是假设冲突很少发生,每个线程在修改数据之前,先获取一个版本号或时间戳,并在更新时检查这个版本号或时间戳,以确保其他线程没有同时修改数据。乐观锁适用于读操作频繁,写操作相对较少的场景。当冲突较少,且并发写入的概率较低时,乐观锁的性能会更好。
悲观锁则是假设冲突经常发生,因此在访问共享资源之前,线程会先获取锁,确保其他线程无法同时访问相同数据,这可能导致 并发性能降低,因为只有一个线程能够访问数据。悲观锁适用于写操作较为频繁,并且写入概率较高的场景。悲观锁可以有效的避免多个线程同时修改相同数据的情况。
乐观锁和悲观锁还有个区别:乐观锁因为比较乐观,所以一般是先做业务逻辑操作,比如参数处理、内存中进行模型组装调整,然后再去更新数据库。悲观锁因为比较悲观,所以会先尝试加锁,然后再去做业务逻辑操作。
也就是说,乐观锁是先干活,后加锁。悲观锁是先加锁,再干活。
在高并发写操作时,你干了一堆活,把要做的事都准备好了,结果最后去数据库那更新的时候发现版本号变了,纯纯的纯爱战神啊。
所以,应该是先尝试获取锁,如果锁成功,在进行业务逻辑的操作,否则就直接返回失败。
综上,在高并发的场景中,一般来说并发写入的冲突比较频繁,所以建议优先考虑悲观锁。即在做并发操作前,想先尝试获取锁,如果锁成功,再进行业务操作,否则直接返回失败。
比如,我们通常在并发场景下都使用分布式锁,即先添加分布式锁,然后再操作。这个就是一个悲观锁的思想。
乐观锁无锁?
使用乐观锁在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般实现乐观锁的方式就是记录数据版本。如果你认为乐观锁的这个过程中完全没有任何锁的参与的话,那就错了。
虽然在使用乐观锁的时候,我们没有显式的加锁,也没有用到对他的相关锁机制。但是乐观锁是使用 update 语句过程中实现的, update 的过程是有锁的。
数据库在更新的时候,会根据 where 条件中是否包含索引考虑加锁范围,如果有索引,那么就是用索引5添加行级锁,如果没有索引,那么就会添加表级锁。
所以,乐观锁的过程中,并不是完全无锁的。
那么,既然乐观锁也有锁,那么他相比悲观锁的意义在哪里呢?
乐观锁最大的好处就是通过CAS(Compare And Swap)的方式做并发校验,这个过程不需要提前加锁,只需要在更新的那一刻加一个短暂的锁而已,而悲观锁的话,需要你先 select for update ,锁的时长更长。
什么是CAS
CAS是一项乐观锁技术,Compare And Swap 的简称,顾名思义就是先比较再替换。CAS 包含三个操作数---内存位置V, 预期原值A 和 新值V。在并发修改的时候,会先比较A和V中取出的值是否相等,如果相等,则会把值替换成B,否则不做任何修改。
当多个线程尝试使用CAS同时更新同一个变量时 ,只有其中一个线程能更新变量的值,其他线程都失败,失败的线程并不会失败,而是被告知这侧竞争失败,并可以再次尝试。
ABA问题
CAS算法实现一个重要前提是需要取出内存中某时刻的数据,而在下时刻比较并替换,那么在这个时间差会导致数据的变化。
比如说当一个线程想要更新一个共享变量,初次读到这个值是A,再次准备赋值时这个值依然是A,但不能表名这个值没有被其他线程修改过,因为他可能在这段时间经过从A到B然后又被修改为A的两次修改操作,这就是ABA问题。
解决方法:在变量前面添加版本号或时间戳。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!