2020-09-04

Spring事务中含有Synchronized锁会发生什么?


问题描述:

在学习线程的时候,sleep()不会释放锁,只能在Synchronized方法块执行完的时候释放。于是想到自己之前写的一段代码,在@Transactional()下的方法中写入了一个Synchronized方法块,会不会出问题?

业务场景是这样,发放优惠券10000张,为了避免在领取优惠券的时候出现线程安全问题,没有使用悲观锁和乐观锁,就加入了Synchronized方法块。

废话不多说,直接上代码。

100个测试线程:

Service层代码:

sql代码(没有用悲观锁和乐观锁):

测试前结果:

测试结果:

你没看错,执行之后数量只增加了9,那么其他91条哪儿去了呢?为什么会是这样的结果?

下面是部分日志打印:

最后执行sql日志打印:

由日志可见这些sql的日志执行是没有顺序,虽然已经到524,但是最后执行的还是519,所以我们所见的结果还是519。

问题出在哪里?是不是由于锁在事务中,在事务还没有commit的时候,下一个线程就已经获取了锁,从而导致读取的是commi之前,数据库的数据?

把事务注解去掉测试一下:

测试结果:

结果是对的,再看日志打印:

可见,这是一个有序的执行过程,结果正确;


解决方案:

显然,上述方式不足以解决我们的问题,但是我们知道,在事务中使用锁,其实并不能保证线程安全,那么在锁中使用事务呢?

修改方案如下:

service代码:

执行结果:

执行结果正确,再看日志打印:

执行也是有序的。之前的错误数据是在结束了Synchronized方法块之后但是在提交之前,别的线程读取了数据,然后最后执行的提交数据决定数据的结果。之后写代码还是要避免这种情况,还是要多想想,在代码中发生的细节过程,避免出现bug。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值