悲观锁 & 乐观锁的原理及应用场景

本文深入探讨了悲观锁和乐观锁的概念,分析了它们在多写和多读场景下的应用,以及如何通过version版本号机制和CAS算法实现乐观锁。同时,对比了悲观锁与乐观锁在并发控制上的差异,以及它们在MySQL、Java和Redis等数据库中的具体实现。
摘要由CSDN通过智能技术生成

目录

1. 悲观锁

应用场景:多写场景,线程安全

2. 乐观锁

应用场景:多读场景,提高吞吐量


悲观锁和乐观锁其实核心就一个是否支持多线程并发的问题。

1. 悲观锁

顾名思义就是很悲观,每次拿数据都会认为别的线程会修改该数据,所以会给数据上锁;

这样抢到锁的线程运行,取到数据做操作,

这期间其他线程想要访问该数据时,都是阻塞block挂起状态,操作不了;

核心就是不支持多并发,是单线程操作,通过抢占时间片的方式来抢锁的使用权,把并发变成了串行。

共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程。

 

应用场景:

悲观锁适用于多写的场景,保证线程安全和数据安全

mysql的行锁、表锁、读锁、写锁;

java中的synchronized。

 

2. 乐观锁

顾名思义就是很乐观,每次拿数据都认为别的线程不会修改数据,因此不会给数据上锁;

但会在数据更新时判断一下,在此期间其他线程有没有对该数据做更新,最终通过多个线程的逐一更新获取数据的最终值;

判断单一线程操作数据期间,其他线程有没有对该数据做修改用的是,version版本号机制、CAS算法。

乐观锁支持多线程并发,每个线程在不同的时间节点对数据做更新操作,每次更新时候都会判断其他线程是否对数据做了更新。

(1)version版本号机制

一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。

当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

sql源码:

update table set x=x+1, version=version+1 where id=#{id} and version=#{version};  

(2)CAS算法机制

即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。

 

应用场景:

乐观锁适用于多读的场景,获取数据不再创建、销毁锁,减少了锁的开销,加大了数据的吞吐量,

Redis等非关系型数据库

ps:Redis是单线程操作,把事务封闭在单一线程中,避免了线程的安全问题,所以里面没有加悲观锁;

       不过对于依赖多个Redis操作的复合操作来说,还是需要加锁的,而且有可能是分布式锁,也可以用LUA脚本,用任务队列的方式解决多任务并发的问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值