在实际工作中理解乐观锁和悲观锁

4 篇文章 0 订阅
2 篇文章 0 订阅

先把需求提出:在用户提交表单数据后,保存表单数据之前,通过切面手段或硬编码生成一个表单编号放入表单数据中。

 

生成编号的规则是A3501047800002009120003

A+12位单位编码+年月+四位顺序号(按照A+12位单位编码+年月去查询目前的最大值,然后+1) 

如果两个线程A、B同时查出上一个编号是A3501047800002009120003,都做了+1操作,如果数据库表单编号字段没有设置唯一的话,就会出现两条一样的编号。

这里和好友讨论后得出了两种解决方案,分别是基于乐观锁和悲观锁来的。

乐观锁解决方案:

我们认为这个并发场景不会经常出现,或者是并发量并不是很大。伪代码实现方案如下:

while(true){

select查出最大值;然后+1

try{

insert;

break;

}catch(uniqueException){ //数据库唯一性限定异常,把CAS算法中的C交给了数据库唯一性校验保证

continue;    //自旋

这个方案的前提是数据库中,该表单编号字段必须是唯一限定的,当和朋友讨论出这种方案的时候,恍然想起,这不就是CAS算法吗:JAVA中对CAS算法的应用

这种自旋无锁式的编码虽然能保证并发安全,并且省去了进入阻塞和获取锁的开销,但是并发量大的时候,自旋中会不停的查询并尝试插入数据,对数据库的压力会增大。这种乐观锁由于是基于数据库唯一性校验的,所以在分布式环境中,如果分库了,我们还需要对单位编号做hash运算,和分库个数取模找到需要存入的数据库,依然能保证唯一性。

悲观锁解决方案:

通过synchronized/ReentrantLock来让其他线程进入阻塞状态,这种方式是当自旋开销已经远远大于线程进入阻塞和获取锁时的开销了,就是并发量大的时候。但这只适用在同一个进程中,如果是集群就不行了。在集群模式下,还需要引入分布式锁,我第一个想到的方案就是用redis来实现。通过redis提供的setnx方法(SET IF NOT EXIST),这原理其实就是让集群中的所有进程共享一个变量,通过共享变量的模型来达到进程之间的同步。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值