文章目录
  1. 1. Redis实现分布式锁
    1. 1.1. 一、Redis特性
    2. 1.2. 二、分布式锁的要求
    3. 1.3. 三、实现锁的重要命令

Redis实现分布式锁

一、Redis特性

  • Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问。
  • 多客户端对redis的连接并不存在竞争关系。
  • Redis命令操作具有原子性。

二、分布式锁的要求

  • 安全性: 互斥,在任何时候,只有一个客户端能持有锁。
  • 活跃性A:没有死锁,即使客户端在持有锁的时候崩溃,最后也会有其他客户端能获得锁,有超时机制。
  • 活跃性B:故障容忍,只有大多数Redis节点时存活的,客户端仍可以获得锁和释放锁。

三、实现锁的重要命令

SETNX key value

当且仅当key不存在时,将key的值设为value,返回1
若给定的key已经存在,则SETNX不做任何动作,返回0

GETSET key value

将给定key的值设为value,返回key对应的旧的value
当key存在但不是字符串类型时,返回一个错误
当key不存在时,返回nil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//上锁
private boolean acquireLock(Long tenantId, String lockKey, long expired) {
boolean success = false;
long value = System.currentTimeMillis() + expired;
//通过SETNX试图获取一个lock
boolean flag = cacheClient.setnx(tenantId, lockKey, String.valueOf(value));
//SETNX成功,则成功获取一个锁
if (flag) {
success = true;
} else {
//SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时(GET方法获取oldValue)
long oldValue = Long.valueOf(cacheClient.get(tenantId, lockKey));
//如果超时,使用GETSET
if (oldValue < System.currentTimeMillis()) {
String getValue = cacheClient.getSet(tenantId, lockKey, String.valueOf(value));
// 如果oldValue与getSet获得的相同,则该线程获取锁成功
if (Long.valueOf(getValue) == oldValue) {
success = true;
} else {//否则,已被其他进程捷足先登
success = false;
}
} else {//未超时,则直接返回失败
success = false;
}
}
return success;
}
//解锁
private void unLock(Long tenantId, String lockKey) {
//如果在获取锁的情况下,操作超时,那么锁有可能会被其他线程夺走
//所以在调用前判断下自身是否已经超时
cacheClient.del(tenantId,lockKey);
}

文章目录
  1. 1. Redis实现分布式锁
    1. 1.1. 一、Redis特性
    2. 1.2. 二、分布式锁的要求
    3. 1.3. 三、实现锁的重要命令