分布式锁实现方案

4 篇文章 0 订阅
3 篇文章 0 订阅

在高并发场景中,我们需要对资源上锁。比如在秒杀商品时,大量请求过来,不上锁可能导致超卖等现象的发生。

大家都知道在java中,它自身就提供了很多锁,synchronized,lock,ReentrantLock....

它们可以工作在单机项目里面,但是在分布式项目里面,他们就不能保证对全局资源的掌控了。

那如何实现在分布式环境中对全局资源的掌控呢?(声明,此处只探讨数据库和redis实现

1.数据库实现

数据库又分乐观锁和悲观锁

悲观锁的实现思路:使用for update来锁住记录,当有别的线程同时来修改的时候,就会去等待,是不是有点像synchronized的实现(synchronized实现原理也是多个线程一起来请求,只有一个线程可以获取锁变成owner,其他没有获取锁的线程在moniter enter区等待)

乐观锁的实现思路:在行字段中添加version字段,取出version对比。如果自己拿到的版本号和当前库里面的记录是一样的就更新记录。否则不做处理,怎么感觉有点像cas。(cas里面的实现原理简单来说就是程序自旋,如果自己手上的值和变量当前的值一样,就做update处理,否则就啥也不干)

采用数据库实现,终究服务器压力全部都到数据库上面了。不管是乐观锁还是悲观锁实现,就算数据库搞成集群模式,它的承受能力都是有限的。并不推荐使用数据库模式做锁。

2.借助第三方redis实现

这是主要要讲解的点。

其实对于锁的使用来说,终究还是要看场景的。

1)用户抢购某种商品,如果当次请求没有抢到锁,可以立即返回一个未抢到,再次请抢购的的提示。

2)用户抢购某种商品,如果当前没有获得锁,将当前线程添加到同步队列中获取锁资源,锁需要考虑过期时间限制来防止死锁。

之前有一种解决方法是 利用redis的set方法

 /**
     * 存储数据到缓存中,并制定过期时间和当Key存在时是否覆盖。
     *
     * @param key
     * @param value
     * @param nxxx 
     *     nxxx的值只能取NX或者XX,如果取NX,则只有当key不存在是才进行set,如果取XX,则只有当key已经存在时才进行set
     * 
     * @param expx expx的值只能取EX或者PX,代表数据过期时间的单位,EX代表秒,PX代表毫秒。
     * @param time 过期时间,单位是expx所代表的单位。
     * @return
     */

    String set(String key, String value, String nxxx, String expx, long time);

由于redis是单线的的,这个set方法正好可以做分布式下面的锁。

获取锁:如果key不存在,set方法返回“ok”,当前线程添加锁成功,别的线程无法获得锁。

释放锁:通过lua脚本的原子操作来释放锁。redis.call('del',key)。

这种方案确实可以实现锁,但是它却不是可重入的。后面发现redis本身是提供可重入锁的。有点像Reentrantlock。可参考redisson的reentrant-lock


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值