记一次多线程处理思考

兜兜转转,磕磕绊绊了很久,还未来得及想明白自己要什么,就错过了很多。等等,错了,重来一遍。从大学开始,就很喜欢观察身边的一些小事,思考一些小问题,写一些对生活的小感悟,导致现在提笔就开始聊人生谈理想,随着年龄的增长,以及阅历的不断丰富,经历了一些社会的小考验,逐渐褪去了乌托邦式的理想主义.............

今天我想聊的是和朋友一起深入探讨过的一个问题,如何正确的使用乐观锁机制解决多线程下并发问题。

正常case:

第一次,事件A触发执行 更新数据库为status=INIT

第二次,事件B出发执行 更新数据库为name=小明

第三次,事件C触发执行 更新数据库为status=FINISHED

代码逻辑如下:

先定义方法:

执行结果为:

此时我们看到没有任何问题,达到了我们想要的结果。但是在推到测试环境时,出现了一个问题,最终结果没有被更新为FINISHED。

排查日志发现更新FINISHED代码已经执行,但是没有生效,原因是因为调用方在异常情况下会再次以并发方式执行回调,模拟伪代码如下:

执行结果:

解决方案一:悲观锁

对queryById加上排他锁for update使线程同步,但是结果依旧如此,并未解决。因为此时加上事务,在更新FINISHED时,afterFinished方法如果抛出异常,整体业务状态回滚,不符合业务场景,此方法排除。

解决方案二:乐观锁

允许多线程并发乱序执行,在执行B事件时,加上条件判断,如果是非FINISHED则不执行B事件。结果依旧未解决。因为B事件执行时执行了queryByIdForUpdate,B和C事件同时执行,queryByIdForUpdate查询出的map中状态可能是在事件C执行完FINISHED之前的INIT,此时C先执行完毕,状态变更为FINISHED,B开始执行,更新状态为INIT,由于两次forUpdate并非是原子操作,因此,此方式失败。

解决方案二:乐观锁+代码执行顺序修改

允许多线程并发乱序执行,将updateB修改为只修改updateName,并发乱序问题解决。无论并发任何顺序,都只执行更改不同事件下的状态,B事件执行的更新name操作和顺序无关,不影响执行结果。

当你觉得你什么都不知道的时候,其实你已经知道了很多,我们下次见。

关注我,回复”资料“领取更多学习资料,包括阿里等面试题库​

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值