redis分布式锁一般不是阻塞锁,如何实现redis分布式阻塞锁?

redis分布式锁一般不是阻塞锁,如何实现redis分布式阻塞锁?

阅读 10k
3 个回答

阻塞的本质是让客户端线程阻塞等待。

服务器是做不到的,redis也是做不到的。

因此,必然是客户端线程获得锁失败后,自己阻塞。但是同时阻塞后需要有人去定期查看分布式锁是否已被释放或者服务器异步通知客户端分布式锁已被释放。一但释放就去抢锁,成功则唤醒客户端线程。

下面提供一个思路:

(1)阻塞和唤醒线程,比如Java则是 LockSupport.park()LockSupport.unpark(thread)

(2)定期获得锁方式,设计一个同步容器,看是否区分公平或非公平而设置为同步有序,或同步无序容器。客户端阻塞前,将Thread.currentThread()加入同步容器。固定的一个定时任务去setnx,获得锁,则在同步容器中选择合适的线程,唤醒他,并告诉他获得锁。

(3)唤醒方式也类似增加同步容器。采用pub, sub,固定的线程等待redis发布消息,获得后,唤醒客户端线程,让客户端线程自己去setnx获得锁。但是有个问题,redis并不能自己publish消息,需要进一步实现,比如客户端释放锁后发布消息,存在获得锁的客户端崩溃导致分布式锁过期释放但没人发布锁释放的消息。因此,此类方式只能作为辅助手段。

题外话,既然有阻塞了,相当于线程已经不关注获得锁的性能了,推荐使用zookeeper分布式锁。

结合队列brpop命令试试?

想了很久没想明白为啥会想要一个堵塞的锁。

我想你既然都允许堵塞了,也就是说不是很着急做这个任务,那么你可以轮询锁,等你得到锁的时候再执行。这个方法应该是最简单了。

假如你这个任务是必须做的,即使你的服务重启后也必须继续做没有做完的任务,那你可以用队列,rabbitMq是一个选择。

当然,redis的有序集合也是可以做队列的。

我错了,确实有这种需求。假如一个用户付费购买会员,假如他连续支付了两次,因为付款结果是异步得到的,这两次结果会有可能同时到达。而这两次支付也必须处理,且只能先处理完一个再处理下一个。

这种情况不着急处理,但需尽快处理,因为用户在等着。

这里还是建议用队列,锁还是redis无堵塞锁。消费者遇到有锁时,不要ack该消息且直接放弃。然后队列会马上把这条消息重新发送给别的消费者(也可能是同一个消费者)。然后不断循环,直到锁被解开。

当然,消费者里也可以用轮询的方式不断尝试获取锁,只要不ack消息,这条消息就不会丢。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题