一个操作需要进行读变量,写变量两个步骤,多个相同的操作同时进行就会出现并发问题。因为读取和写入两个变量不是原子操作。

redis分布式锁实战 redis分布式锁的使用_分布式锁

分布式锁

分布式锁本质上要实现的目标就是在 Redis 里面占一个“茅坑”,当别的进程也要来占时,发现已经有人蹲在那里了,就只好放弃或者稍后再试。

占坑一般是使用 setnx(set if not exists) 指令,只允许被一个客户端占坑。先来先占, 用完了,再调用 del 指令释放茅坑。

加锁

setnx lock:a true

释放锁

del lock:a

为了避免加锁后,中间操作出现异常,最后没有释放锁的问题,需要给锁设置一个超时时间。

setnx lock:a true
expire lock:a 5

出现另一个问题,上面的操作也有可能失败,例如设置过期时间失败。

为了解决上述的问题,Redis2.8增加了set指令的扩展参数,

set lock:a true ex 5 nx

要确保分布式锁可用,需至少要满足下面四个条件:

  • 互斥性:只能一个客户端持有锁
  • 不会发生死锁
  • 具有容错性
  • 解铃还须系铃人

超时问题

如果执行代码的时间太长,超出了锁的超时限制,就会由其他线程获得锁。会导致代码不能严格被执行。为了避免这个情况,进行加锁的执行代码尽量不要选择执行时间过长的。

可重入性

可重入性指的是线程在持有锁的情况下,再次请求加锁。

问题,为何要设计可重入这一个特性?

搞清楚几个概念:可重入锁、公平锁、非公平锁。

可重入锁:
线程1执行 synchronized A()方法,A()方法调用synchronized B()方法,当线程1获取到A方法对应的对象锁之后,再去调用B方法,就不需要重新申请锁。

公平锁:
多个线程等待锁,当锁释放后,等待该锁时间最久的(或者说最先申请锁的),应该获得锁。

非公平锁:
多个线程等待锁,不按照等待锁的时间或申请锁的先后顺序,来获得锁。

Redlock 算法

参考文档

[1]: 《Redis 深度历险:核心原理与应用实践》 [2]: 通过一个故事理解可重入锁的机制 [3]: JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁 [4]: 80% 人不知道的 Redis 分布式锁的正确实现方式(Java 版) [5]: Java 框架之Redis 分布式缓存 [6]: 【肥朝】面试官问我,Redis分布式锁如何续期?懵了。 [6]: Redis分布式锁的正确实现方式(Java版)