浅谈对于乐观锁和悲观锁的理解

今儿回忆了一下关于乐观锁和悲观锁的知识,要唠唠这两个点,那先得知道什么是锁?

1.锁的定义:锁是一种互斥的机制,在多线程环境中实现对资源的协调与控制,凡是有资源被多线程共享,涉及到修改的情况就要考虑锁的加持。

2.锁的分类:锁的种类很多,此处罗列下常见的或者听过的分类——①乐观锁/悲观锁;②独享锁/共享锁;③分段锁;④可重入锁;⑤公平锁/非公平锁;⑥锁升级(无锁→偏向锁→轻量级锁→重量级锁);⑦互斥锁/读写锁;⑧分布式锁……(锁的种类很多,应用场景更多,感兴趣小伙伴可以找找资料)

知道了关于锁的基本概念,那么今儿主要唠唠乐观锁和悲观锁——

悲观锁

定义:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。

解释:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。

理解:多线程场景下,当一个线程A来操作数据对象时,线程A特别悲观,就怕还有线程B、线程C等小伙伴也想来操作同一个数据对象,因此线程A就会对要操作的数据对象加上一把锁,这样别人想拿这个数据就会block,直到它操作完并释放掉锁之后才给其他线程来操作(可以怀疑线程A是大男子主义,有理有据=。=)。

实现:Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被block。

应用:悲观锁会影响并发性能,适合写多读少的场景。

乐观锁

定义:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

解释:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。

理解:多线程场景下,当一个线程A来操作数据对象时,线程A是个乐天派,他操作的过程中,不怕线程B、线程C等小伙伴一起来操作,但是处于对数据对象的负责任态度,为了保证数据一致性和完整性,在提交数据前,会先校验一下,还有没有其他人操作这个数据了,如果没有人操作,就更新数据对象,如果有人操作过了,那就放弃本次操作(乐观锁是个暖男,妥妥的)。

实现:常见的实现方式有两种:

①使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。 

②使用时间戳(timestamp)。乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

Java JUC中的atomic包就是乐观锁的一种实现,AtomicInteger 通过CAS(Compare And Set)操作实现线程安全的自增。

应用:乐观锁可以提高吞吐量,适合读多写少的场景。

以上就是对于乐观锁和悲观锁的一些基本概念了,继续搬砖~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值