乐观锁和悲观锁

23
四月
2021

文章目录

  • 一、分别是什么?
    • 1、乐观锁
    • 2、悲观锁
  • 二、如何选择?

一、分别是什么?

1、乐观锁

乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。

乐观锁的实现:

  • CAS(Compare and Swap)实现:Java中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种CAS实现方式。
  • 版本号控制:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数。当数据被修改时,version值会+1。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值与当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

版本号控制实践案例:
1、点击文件修改时先加锁

update table set lockUser = xxxx ,modifyTime = sysdate,lockStatus = lock where id='' and (lockStatus=unlock or lockUser = xxxx or modifyTime < 5分钟前);

2、提交文件修改时,根据版本号控制加锁

update table set version = version+1,lockStatus = unlock where id = xxxx and version = xxxx;

2、悲观锁

悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。

悲观锁的实现:

  • 传统的关系型数据库使用这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
  • Java里面的同步synchronized关键字的实现

二、如何选择?

两种锁各有优缺点,不能单纯的定义哪个好于哪个。
乐观锁比较适合读取比较频繁、数据修改比较少的场景,即使出现了少量的修改冲突,这样也省去了大量的锁的开销,故而提高了系统的吞吐量。但是如果经常发生冲突(数据修改比较频繁的情况下),触发上层应用不断的重试,这样反而浪费了开销,降低了性能,对于这种情况使用悲观锁就更合适。

  • 1、响应效率:如果需要非常高的响应速度,建议采用乐观锁方案,不需要等待其他并发去释放锁。
  • 2、冲突频率:如果冲突频率非常高,建议采用悲观锁,保证成功率。冲突频率大,选择乐观锁会需要多次重试才能成功,代价比较大。
  • 3、重试代价:如果重试代价大,建议采用悲观锁。
TAG

网友评论

共有访客发表了评论
请登录后再发布评论,和谐社会,请文明发言,谢谢合作! 立即登录 注册会员