redis分布式锁剖析

如何用Redis实现分布式锁?

1
https://juejin.im/post/6844903616667451399

加锁

1
2
3
4
5
6
7
8
9
10
String threadId = Thread.currentThread().getId()

if(set(key,threadId,30,NX) == 1 ) {
try{
dosth()
}finally{
if(threadId == redis.get(key))
del(key)
}
}

解锁:

1
2
3
4
5
if(threadId .equals(redisClient.get(key))){

del(key)

}

为什么要线程的ID?

如果某些原因导致线程B执行的很慢很慢,过了30秒都没执行完,这时候锁过期自动释放,线程B得到了锁。随后,线程A执行完了任务,线程A接着执行del指令来释放锁。但这时候线程B还没执行完,线程A实际上删除的是线程B加的锁。

怎么避免这种情况呢?可以在del释放锁之前做一个判断,验证当前的锁是不是自己加的锁。至于具体的实现,可以在加锁的时候把当前的线程ID当做value,并在删除之前验证key对应的value是不是自己线程的ID。

用lua脚本来保证原子性

并发可能性

还是刚才第二点所描述的场景,虽然我们避免了线程A误删掉key的情况,但是同一时间有A,B两个线程在访问代码块,仍然是不完美的。

怎么办呢?我们可以让获得锁的线程开启一个守护线程,用来给快要过期的锁“续航”。

当过去了29秒,线程A还没执行完,这时候守护线程会执行expire指令,为这把锁“续命”20秒。守护线程从第29秒开始执行,每20秒执行一次。