当前位置:网站首页>乐观锁与悲观锁
乐观锁与悲观锁
2022-08-10 08:58:00 【努 力 小 子】
悲观锁
假设最坏的情况,即每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现。
乐观锁
假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
使用范围
乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
乐观锁方法
乐观锁尽管是在多读少写的机制下需要的,依旧会有写入修改的情况存在,那么应该如何实现呢?
版本号机制
版本号机制就是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。说白了,版本号机制就是常见的flag或者标志符,当我们修改写入后自动加一,然后需要时进行比对即可知道是否有写入修改。
CAS算法
compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数:
需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。
ABA问题
如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 "ABA"问题。
JDK 1.5 以后的 AtomicStampedReference 类 中的 compareAndSet 方法 就是先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
长时间不能更新
自旋CAS(不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。 如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体
实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。
共享变量合并
AtomicReference类 保证引用对象之间的原子性,把多个变量放在一个对象里来进行 CAS 操作,可以使用锁或者利用 AtomicReference类 把多个共享变量合并成一个共享变量来操作。
CAS和synchronized
CAS适用于写比较少的情况下(多读场景,冲突一般较少),synchronized适用于写比较多的情况下(多写场景,冲突一般较多)。
- 对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。
- 对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。
边栏推荐
猜你喜欢

明明加了唯一索引,为什么还是产生重复数据?

高性能短连接设计

DAY25: Logic vulnerability recurrence

I don't want to do accounting anymore, Die changed to a new one, moved forward bravely, and finally successfully passed the career change test to double his monthly salary~

2022-08-01 Advanced Network Engineering (24) STP Advanced Knowledge

Spotify使用C4模型表达其架构设计

Uni-app develops WeChat applet using local images as background images

iwemeta metaverse: Ali's first COO: how to build a sales force

How AliExpress sellers seize product search weight

Flink快速上手 完整使用 (第二章)
随机推荐
短视频同城流量宣传小魔推有何优势?如何给实体商家带来销量?
浅谈DAO+DeFi+NFT模式开发代码技术方案丨链游元宇宙NFT盲盒项目技术开发逻辑(源码程序)
FPGA时钟篇(三) MRCC和SRCC的区别
【OAuth2】二十、OAuth2扩展协议 PKCE
[In-depth study of 4G/5G/6G topic-56]: L3 signaling control-5-radio bearer management
以技术御风险,护航云原生 | 同创永益 X 博云举办产品联合发布会
Ask next CDC mysql to Doris. Don't show the specific number of lines, how to do?
Solve the problem that the win10win7win8 system cannot find the specified module and cannot register the desert plug-in
Question brushing tool h
原型和原型链
地平线:面向规模化量产的智能驾驶系统和软件开发
日期类(暑假每日一题 19)
高性能短连接设计
并查集模板
钻石价格预测的ML全流程!从模型构建调优道部署应用!
mySQL add, delete, modify and check advanced
PTA Exercise 2.2 Rotate an Array Left
iwemeta metaverse: a doll sells for 9999 yuan, and Bubble Mart thinks it is not expensive at all
StringUtils的具体操作
Class Notes (7) (1) - #647. Find the root and the child (root)