当前位置:网站首页>【Redis实现秒杀业务③】超卖问题之乐观锁具体实现
【Redis实现秒杀业务③】超卖问题之乐观锁具体实现
2022-06-24 20:01:00 【步尔斯特】
版本号法
版本号机制实现的方式常用的也有两种:
使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。
当我们提交更新的时候,判断数据库表对应记录 的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修 改,那么,先提交的操作会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。使用时间戳(timestamp)。这种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

CAS算法
CAS即Compare And Swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。
CAS操作包含三个操作数——内存位置的值(V)、预期原值(A)和新值(B)。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。
通过乐观锁+自旋的方式,解决数据更新的线程安全问题,而且锁粒度比互斥锁低,并发性能好。
循环实现:
public void addCount(String goodsId, Integer count) {
while(true) {
Goods goods = dao.selectByGoodsId(goodsId);
if (goods == null) {
throw new Execption("数据不存在");
}
int count = goods.getCount() + count;
goods.setCount(count);
int count = dao.updateCount(goods);
if (count > 0) {
return;
}
}
}
递归实现:
public void addCount(String goodsId, Integer count) {
Goods goods = dao.selectByGoodsId(goodsId);
if (goods == null) {
throw new Execption("数据不存在");
}
int count = goods.getCount() + count;
goods.setCount(count);
int count = dao.updateCount(goods);
if (count == 0) {
addCount(goodsId, count)
}
}
CAS算法的缺点
【1】循环时间长开销很大:自旋 CAS 如果长时间不成功,会给 CPU 带来非常大的执行开销。
【2】只能保证一个共享变量的原子操作:只能保证一个共享变量的原子操作。当对一个共享变量执行操作时,我们可以使用循环 CAS的方式来保证原子操作,但是对多个共享变量操作时,循环 CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量 i=2,j=a,合并一下 ij=2a,然后用CAS 来操作 ij。从 Java1.5 开始 JDK 提供了 AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作。
【3】ABA 问题:因为 CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用 CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A-B-A 就会变成1A-2B-3A。
图解

代码实现
我们可以通过如下这种方式进行处理,如果数量和自己查到的数量相等,就购买
// 如果数量和自己查到的数量相等,就购买
boolean updateBoolean = this.update().setSql("count = count - 1")
.eq("id", id).eq("count", fruits.getId()).update();
if (!updateBoolean) {
return ResponseEntity.status(400).body("水果卖光了,下次再来吧!");
}
但是这样会让其他本应该可以购买的用户买不了,所以改动如下
// 如果数量和自己查到的数量相等,就购买
// boolean updateBoolean = this.update().setSql("count = count - 1")
// .eq("id", id).eq("count", fruits.getId()).update();
// 如果剩余数量大于0,就可以购买
boolean updateBoolean = this.update().setSql("count = count - 1")
.eq("id", id).gt("count", 0).update();
if (!updateBoolean) {
return ResponseEntity.status(400).body("水果卖光了,下次再来吧!");
}
边栏推荐
- Collective example
- Tiktok wallpaper applet v1.0.2 function, new arrival function
- Wallpaper applet wechat applet
- Time unified system
- 实现mnist手写数字识别
- [proteus simulation] example of using timer 0 as a 16 bit counter
- Eliminate duplicate dependencies
- 2021-11-07
- 5-minute NLP: summary of 3 pre training libraries for rapid realization of NER
- VIM use command
猜你喜欢

Collective example

Go crawler framework -colly actual combat (II) -- Douban top250 crawling

OTT营销之风正盛,商家到底该怎么投?
Modstart: embrace new technologies and take the lead in supporting laravel 9.0

On the difficulty of developing large im instant messaging system

Time unified system

Ansible及playbook的相关操作

Go crawler framework -colly actual combat (4) -- Zhihu answer crawl (2) -- visual word cloud
Is it so difficult to calculate the REM size of the web page according to the design draft?

Color gradient gradient color collection
随机推荐
Scrollview height cannot fill full screen
Creative SVG ring clock JS effect
Technologie des fenêtres coulissantes en octets dans la couche de transmission
What is test development? Can you find a job at this stage?
软件测试与游戏测试文章合集录
Dry and wet contacts
Virtual machine - network configuration
Do280openshift access control -- encryption and configmap
Some examples of MgO operating database in go
Usage of ViewModel and livedata in jetpack
Design and practice of vivo server monitoring architecture
Binder mechanism and Aidl communication example
MySQL semi sync replication
VNC viewer remote connection raspberry pie without display
Tiktok wallpaper applet source code
Domain Driven Design and coding
Paper review: U2 net, u-net composed of u-net
Overview of medium and low speed aerospace electronic bus
@mysql
Signal integrity (SI) power integrity (PI) learning notes (XXV) differential pair and differential impedance (V)