乐观锁存在的Bug

数据表中:记录 x.value = 50, y.value = 50;
假设 支付宝 中,x、y 是 情侣,对于每对情侣总金额小于100元的,支付宝决定赠送 100元 红包。

线程1:
if (x.value + y.value <= 100) {
x.value += 100;
}

线程2:
if (x.value + y.value <= 100) {
y.value += 100;
}
```
线程1 执行 if 后,线程2再执行if,都满足条件。
接着线程1修改x的值,再提交,发现x的版本号没变,修改成功,x版本号加1:x.value = 150 
然后线程2修改y的值,再提交,发现y的版本号没变,修改成功,y版本号加1:y.value = 150 
支付宝就损失了 100 元。

这好像不是锁的问题而是你的逻辑的问题,是不是歌词下载这种操作,每次应该修改x,y两个的版本号,而不是单一个

没看懂你说的什么意思,我就没看到你加锁,线程不安全什么可能都会发生,亏钱不稀奇。

你这根本就不是乐观锁好吧,兄弟.
乐观锁的compareAndSet是原子操作,这是硬件层面支持的,如果落到数据库上,一条记录也是有行锁的,你的compare和set根本就不是原子的.
建议仔细研究下java的CAS锁机制,或者数据库的乐观锁实现,都是类似的.

你的示例代码并不是CAS,完整的乐观锁总会有个自旋操作

建议仔细看清我说的,我说的是 数据表 中。不是 Java 并发操作,不是Java中的乐观锁。而是数据库事务并发修改。

百度原文:相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据 库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

建议去研究下 MyBatis 或 Hibernate 中 有关乐观锁的实现。

阿里编程规范中 就说明 凡是 涉及到 数据库金额方面的修改 禁止使用 乐观锁。

根据两条数据判断的 ,你就更新一条的version ,当然出问题啦

1.虽然你说了是数据库,但看起来像把数据查询出来再去update哈(这个就不发散了)
2.数据库的乐观锁可不是你这么做的
乐观锁实现是这样子的
select col1,version from table where id = n;
查到version = 1;
update table set col1 = x,version = version + 1 where id = n and version = 1;
如果当时存在多个线程同时更新,那第二个线程如果查询到version = 1的数据再去更新时,他是更新不到的,因为version已经变成2了.
所以为什么说你这个根本不是乐观锁的实现好吧.出现竞争那自然要处理异常,有的需要自旋,有的直接抛弃,根据你业务决定
3.为啥阿里规范要禁止这种做法,我是不清楚的,但也没必要把他的做法当作圣经,人家的业务场景跟你不一样,不能一概而论.

发布了122 篇原创文章 · 获赞 2 · 访问量 5217

猜你喜欢

转载自blog.csdn.net/liuji0517/article/details/105089349